diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-29 13:48:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-29 13:48:48 -0400 |
commit | e389f9aec689209724105ae80a6c91fd2e747bc9 (patch) | |
tree | 3cc88a3e785e4f2ffeaa9dad0da695cfa437d4fe /drivers | |
parent | f73b0a08eae0e28c50db5dd5ab8245546918bfb6 (diff) | |
parent | b4cf205846463a0a23a917bb18ad833bc9a8c0bb (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: (107 commits)
smc911x: fix compilation breakage wjen debug is on
[netdrvr] eexpress: minor corrections
add NAPI support to sb1250-mac.c
ixgb: ROUND_UP macro cleanup in drivers/net/ixgb
e1000: ROUND_UP macro cleanup in drivers/net/e1000
Generic HDLC sparse annotations
e100: Optionally use I/O mode only to access register space
e100: allow bad MAC address when running with invalid eeprom csum
ehea: fix for dlpar support
ehea: fix for sysfs entries
3C509: Remove unnecessary include of <linux/pm_legacy.h>
NetXen: Fix for vmalloc issues
NetXen: Fixes for Power PC architecture
NetXen: Port swap feature for multi port cards
NetXen: Removal of redundant macros
NetXen: Multi PCI support for Quad cards
NetXen: Removal of redundant argument passing
NetXen: Use multiple PCI functions
[netdrvr e100] experiment with doing RX in a similar manner to eepro100
[PATCH] ieee80211: add missing global needed by IEEE80211_DEBUG_XXXX
...
Diffstat (limited to 'drivers')
147 files changed, 29194 insertions, 6033 deletions
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index c7511c4d3b68..9588da3a30e7 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c | |||
@@ -83,7 +83,6 @@ static int max_interrupt_work = 10; | |||
83 | #include <linux/netdevice.h> | 83 | #include <linux/netdevice.h> |
84 | #include <linux/etherdevice.h> | 84 | #include <linux/etherdevice.h> |
85 | #include <linux/pm.h> | 85 | #include <linux/pm.h> |
86 | #include <linux/pm_legacy.h> | ||
87 | #include <linux/skbuff.h> | 86 | #include <linux/skbuff.h> |
88 | #include <linux/delay.h> /* for udelay() */ | 87 | #include <linux/delay.h> /* for udelay() */ |
89 | #include <linux/spinlock.h> | 88 | #include <linux/spinlock.h> |
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index a3d46ea37126..545c405a5cb0 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -486,8 +486,8 @@ config SGI_IOC3_ETH_HW_TX_CSUM | |||
486 | enables offloading for checksums on transmit. If unsure, say Y. | 486 | enables offloading for checksums on transmit. If unsure, say Y. |
487 | 487 | ||
488 | config MIPS_SIM_NET | 488 | config MIPS_SIM_NET |
489 | tristate "MIPS simulator Network device (EXPERIMENTAL)" | 489 | tristate "MIPS simulator Network device" |
490 | depends on MIPS_SIM && EXPERIMENTAL | 490 | depends on NET_ETHERNET && MIPS_SIM |
491 | help | 491 | help |
492 | The MIPSNET device is a simple Ethernet network device which is | 492 | The MIPSNET device is a simple Ethernet network device which is |
493 | emulated by the MIPS Simulator. | 493 | emulated by the MIPS Simulator. |
@@ -1444,7 +1444,8 @@ config CS89x0 | |||
1444 | 1444 | ||
1445 | config TC35815 | 1445 | config TC35815 |
1446 | tristate "TOSHIBA TC35815 Ethernet support" | 1446 | tristate "TOSHIBA TC35815 Ethernet support" |
1447 | depends on NET_PCI && PCI && TOSHIBA_JMR3927 | 1447 | depends on NET_PCI && PCI && MIPS |
1448 | select MII | ||
1448 | 1449 | ||
1449 | config DGRS | 1450 | config DGRS |
1450 | tristate "Digi Intl. RightSwitch SE-X support" | 1451 | tristate "Digi Intl. RightSwitch SE-X support" |
@@ -2291,14 +2292,10 @@ config UGETH_FILTERING | |||
2291 | bool "Mac address filtering support" | 2292 | bool "Mac address filtering support" |
2292 | depends on UCC_GETH | 2293 | depends on UCC_GETH |
2293 | 2294 | ||
2294 | config UGETH_TX_ON_DEMOND | 2295 | config UGETH_TX_ON_DEMAND |
2295 | bool "Transmit on Demond support" | 2296 | bool "Transmit on Demand support" |
2296 | depends on UCC_GETH | 2297 | depends on UCC_GETH |
2297 | 2298 | ||
2298 | config UGETH_HAS_GIGA | ||
2299 | bool | ||
2300 | depends on UCC_GETH && PPC_MPC836x | ||
2301 | |||
2302 | config MV643XX_ETH | 2299 | config MV643XX_ETH |
2303 | tristate "MV-643XX Ethernet support" | 2300 | tristate "MV-643XX Ethernet support" |
2304 | depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32) | 2301 | depends on MOMENCO_OCELOT_C || MOMENCO_JAGUAR_ATX || MV64360 || MOMENCO_OCELOT_3 || (PPC_MULTIPLATFORM && PPC32) |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 58527322a39d..59c0459a037c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -18,7 +18,7 @@ gianfar_driver-objs := gianfar.o \ | |||
18 | gianfar_sysfs.o | 18 | gianfar_sysfs.o |
19 | 19 | ||
20 | obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o | 20 | obj-$(CONFIG_UCC_GETH) += ucc_geth_driver.o |
21 | ucc_geth_driver-objs := ucc_geth.o ucc_geth_phy.o | 21 | ucc_geth_driver-objs := ucc_geth.o ucc_geth_mii.o |
22 | 22 | ||
23 | # | 23 | # |
24 | # link order important here | 24 | # link order important here |
diff --git a/drivers/net/chelsio/Makefile b/drivers/net/chelsio/Makefile index 382d23f810ab..743ad8b41b5e 100644 --- a/drivers/net/chelsio/Makefile +++ b/drivers/net/chelsio/Makefile | |||
@@ -4,8 +4,6 @@ | |||
4 | 4 | ||
5 | obj-$(CONFIG_CHELSIO_T1) += cxgb.o | 5 | obj-$(CONFIG_CHELSIO_T1) += cxgb.o |
6 | 6 | ||
7 | cxgb-$(CONFIG_CHELSIO_T1_1G) += ixf1010.o mac.o mv88e1xxx.o vsc7326.o vsc8244.o | 7 | cxgb-$(CONFIG_CHELSIO_T1_1G) += mac.o mv88e1xxx.o vsc7326.o |
8 | cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ | 8 | cxgb-objs := cxgb2.o espi.o tp.o pm3393.o sge.o subr.o \ |
9 | mv88x201x.o my3126.o $(cxgb-y) | 9 | mv88x201x.o my3126.o $(cxgb-y) |
10 | |||
11 | |||
diff --git a/drivers/net/chelsio/common.h b/drivers/net/chelsio/common.h index 787f2f2820fe..8ba702c8b560 100644 --- a/drivers/net/chelsio/common.h +++ b/drivers/net/chelsio/common.h | |||
@@ -322,9 +322,9 @@ struct board_info { | |||
322 | unsigned char mdio_mdiinv; | 322 | unsigned char mdio_mdiinv; |
323 | unsigned char mdio_mdc; | 323 | unsigned char mdio_mdc; |
324 | unsigned char mdio_phybaseaddr; | 324 | unsigned char mdio_phybaseaddr; |
325 | struct gmac *gmac; | 325 | const struct gmac *gmac; |
326 | struct gphy *gphy; | 326 | const struct gphy *gphy; |
327 | struct mdio_ops *mdio_ops; | 327 | const struct mdio_ops *mdio_ops; |
328 | const char *desc; | 328 | const char *desc; |
329 | }; | 329 | }; |
330 | 330 | ||
diff --git a/drivers/net/chelsio/cphy.h b/drivers/net/chelsio/cphy.h index cf9143499882..79d855e267e0 100644 --- a/drivers/net/chelsio/cphy.h +++ b/drivers/net/chelsio/cphy.h | |||
@@ -100,7 +100,7 @@ struct cphy { | |||
100 | 100 | ||
101 | u32 elmer_gpo; | 101 | u32 elmer_gpo; |
102 | 102 | ||
103 | struct cphy_ops *ops; /* PHY operations */ | 103 | const struct cphy_ops *ops; /* PHY operations */ |
104 | int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr, | 104 | int (*mdio_read)(adapter_t *adapter, int phy_addr, int mmd_addr, |
105 | int reg_addr, unsigned int *val); | 105 | int reg_addr, unsigned int *val); |
106 | int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr, | 106 | int (*mdio_write)(adapter_t *adapter, int phy_addr, int mmd_addr, |
@@ -136,7 +136,7 @@ static inline int simple_mdio_write(struct cphy *cphy, int reg, | |||
136 | /* Convenience initializer */ | 136 | /* Convenience initializer */ |
137 | static inline void cphy_init(struct cphy *phy, adapter_t *adapter, | 137 | static inline void cphy_init(struct cphy *phy, adapter_t *adapter, |
138 | int phy_addr, struct cphy_ops *phy_ops, | 138 | int phy_addr, struct cphy_ops *phy_ops, |
139 | struct mdio_ops *mdio_ops) | 139 | const struct mdio_ops *mdio_ops) |
140 | { | 140 | { |
141 | phy->adapter = adapter; | 141 | phy->adapter = adapter; |
142 | phy->addr = phy_addr; | 142 | phy->addr = phy_addr; |
@@ -151,7 +151,7 @@ static inline void cphy_init(struct cphy *phy, adapter_t *adapter, | |||
151 | struct gphy { | 151 | struct gphy { |
152 | /* Construct a PHY instance with the given PHY address */ | 152 | /* Construct a PHY instance with the given PHY address */ |
153 | struct cphy *(*create)(adapter_t *adapter, int phy_addr, | 153 | struct cphy *(*create)(adapter_t *adapter, int phy_addr, |
154 | struct mdio_ops *mdio_ops); | 154 | const struct mdio_ops *mdio_ops); |
155 | 155 | ||
156 | /* | 156 | /* |
157 | * Reset the PHY chip. This resets the whole PHY chip, not individual | 157 | * Reset the PHY chip. This resets the whole PHY chip, not individual |
@@ -160,11 +160,9 @@ struct gphy { | |||
160 | int (*reset)(adapter_t *adapter); | 160 | int (*reset)(adapter_t *adapter); |
161 | }; | 161 | }; |
162 | 162 | ||
163 | extern struct gphy t1_my3126_ops; | 163 | extern const struct gphy t1_my3126_ops; |
164 | extern struct gphy t1_mv88e1xxx_ops; | 164 | extern const struct gphy t1_mv88e1xxx_ops; |
165 | extern struct gphy t1_vsc8244_ops; | 165 | extern const struct gphy t1_vsc8244_ops; |
166 | extern struct gphy t1_xpak_ops; | 166 | extern const struct gphy t1_mv88x201x_ops; |
167 | extern struct gphy t1_mv88x201x_ops; | ||
168 | extern struct gphy t1_dummy_phy_ops; | ||
169 | 167 | ||
170 | #endif /* _CXGB_CPHY_H_ */ | 168 | #endif /* _CXGB_CPHY_H_ */ |
diff --git a/drivers/net/chelsio/gmac.h b/drivers/net/chelsio/gmac.h index 006a2eb2d362..d42337457cf7 100644 --- a/drivers/net/chelsio/gmac.h +++ b/drivers/net/chelsio/gmac.h | |||
@@ -126,7 +126,7 @@ typedef struct _cmac_instance cmac_instance; | |||
126 | struct cmac { | 126 | struct cmac { |
127 | struct cmac_statistics stats; | 127 | struct cmac_statistics stats; |
128 | adapter_t *adapter; | 128 | adapter_t *adapter; |
129 | struct cmac_ops *ops; | 129 | const struct cmac_ops *ops; |
130 | cmac_instance *instance; | 130 | cmac_instance *instance; |
131 | }; | 131 | }; |
132 | 132 | ||
@@ -136,11 +136,7 @@ struct gmac { | |||
136 | int (*reset)(adapter_t *); | 136 | int (*reset)(adapter_t *); |
137 | }; | 137 | }; |
138 | 138 | ||
139 | extern struct gmac t1_pm3393_ops; | 139 | extern const struct gmac t1_pm3393_ops; |
140 | extern struct gmac t1_chelsio_mac_ops; | 140 | extern const struct gmac t1_vsc7326_ops; |
141 | extern struct gmac t1_vsc7321_ops; | ||
142 | extern struct gmac t1_vsc7326_ops; | ||
143 | extern struct gmac t1_ixf1010_ops; | ||
144 | extern struct gmac t1_dummy_mac_ops; | ||
145 | 141 | ||
146 | #endif /* _CXGB_GMAC_H_ */ | 142 | #endif /* _CXGB_GMAC_H_ */ |
diff --git a/drivers/net/chelsio/ixf1010.c b/drivers/net/chelsio/ixf1010.c deleted file mode 100644 index 10b2a9a19006..000000000000 --- a/drivers/net/chelsio/ixf1010.c +++ /dev/null | |||
@@ -1,505 +0,0 @@ | |||
1 | /* $Date: 2005/11/12 02:13:49 $ $RCSfile: ixf1010.c,v $ $Revision: 1.36 $ */ | ||
2 | #include "gmac.h" | ||
3 | #include "elmer0.h" | ||
4 | |||
5 | /* Update fast changing statistics every 15 seconds */ | ||
6 | #define STATS_TICK_SECS 15 | ||
7 | /* 30 minutes for full statistics update */ | ||
8 | #define MAJOR_UPDATE_TICKS (1800 / STATS_TICK_SECS) | ||
9 | |||
10 | /* | ||
11 | * The IXF1010 can handle frames up to 16383 bytes but it's optimized for | ||
12 | * frames up to 9831 (0x2667) bytes, so we limit jumbo frame size to this. | ||
13 | * This length includes ethernet header and FCS. | ||
14 | */ | ||
15 | #define MAX_FRAME_SIZE 0x2667 | ||
16 | |||
17 | /* MAC registers */ | ||
18 | enum { | ||
19 | /* Per-port registers */ | ||
20 | REG_MACADDR_LOW = 0, | ||
21 | REG_MACADDR_HIGH = 0x4, | ||
22 | REG_FDFC_TYPE = 0xC, | ||
23 | REG_FC_TX_TIMER_VALUE = 0x1c, | ||
24 | REG_IPG_RX_TIME1 = 0x28, | ||
25 | REG_IPG_RX_TIME2 = 0x2c, | ||
26 | REG_IPG_TX_TIME = 0x30, | ||
27 | REG_PAUSE_THRES = 0x38, | ||
28 | REG_MAX_FRAME_SIZE = 0x3c, | ||
29 | REG_RGMII_SPEED = 0x40, | ||
30 | REG_FC_ENABLE = 0x48, | ||
31 | REG_DISCARD_CTRL_FRAMES = 0x54, | ||
32 | REG_DIVERSE_CONFIG = 0x60, | ||
33 | REG_RX_FILTER = 0x64, | ||
34 | REG_MC_ADDR_LOW = 0x68, | ||
35 | REG_MC_ADDR_HIGH = 0x6c, | ||
36 | |||
37 | REG_RX_OCTETS_OK = 0x80, | ||
38 | REG_RX_OCTETS_BAD = 0x84, | ||
39 | REG_RX_UC_PKTS = 0x88, | ||
40 | REG_RX_MC_PKTS = 0x8c, | ||
41 | REG_RX_BC_PKTS = 0x90, | ||
42 | REG_RX_FCS_ERR = 0xb0, | ||
43 | REG_RX_TAGGED = 0xb4, | ||
44 | REG_RX_DATA_ERR = 0xb8, | ||
45 | REG_RX_ALIGN_ERR = 0xbc, | ||
46 | REG_RX_LONG_ERR = 0xc0, | ||
47 | REG_RX_JABBER_ERR = 0xc4, | ||
48 | REG_RX_PAUSE_FRAMES = 0xc8, | ||
49 | REG_RX_UNKNOWN_CTRL_FRAMES = 0xcc, | ||
50 | REG_RX_VERY_LONG_ERR = 0xd0, | ||
51 | REG_RX_RUNT_ERR = 0xd4, | ||
52 | REG_RX_SHORT_ERR = 0xd8, | ||
53 | REG_RX_SYMBOL_ERR = 0xe4, | ||
54 | |||
55 | REG_TX_OCTETS_OK = 0x100, | ||
56 | REG_TX_OCTETS_BAD = 0x104, | ||
57 | REG_TX_UC_PKTS = 0x108, | ||
58 | REG_TX_MC_PKTS = 0x10c, | ||
59 | REG_TX_BC_PKTS = 0x110, | ||
60 | REG_TX_EXCESSIVE_LEN_DROP = 0x14c, | ||
61 | REG_TX_UNDERRUN = 0x150, | ||
62 | REG_TX_TAGGED = 0x154, | ||
63 | REG_TX_PAUSE_FRAMES = 0x15C, | ||
64 | |||
65 | /* Global registers */ | ||
66 | REG_PORT_ENABLE = 0x1400, | ||
67 | |||
68 | REG_JTAG_ID = 0x1430, | ||
69 | |||
70 | RX_FIFO_HIGH_WATERMARK_BASE = 0x1600, | ||
71 | RX_FIFO_LOW_WATERMARK_BASE = 0x1628, | ||
72 | RX_FIFO_FRAMES_REMOVED_BASE = 0x1650, | ||
73 | |||
74 | REG_RX_ERR_DROP = 0x167c, | ||
75 | REG_RX_FIFO_OVERFLOW_EVENT = 0x1680, | ||
76 | |||
77 | TX_FIFO_HIGH_WATERMARK_BASE = 0x1800, | ||
78 | TX_FIFO_LOW_WATERMARK_BASE = 0x1828, | ||
79 | TX_FIFO_XFER_THRES_BASE = 0x1850, | ||
80 | |||
81 | REG_TX_FIFO_OVERFLOW_EVENT = 0x1878, | ||
82 | REG_TX_FIFO_OOS_EVENT = 0x1884, | ||
83 | |||
84 | TX_FIFO_FRAMES_REMOVED_BASE = 0x1888, | ||
85 | |||
86 | REG_SPI_RX_BURST = 0x1c00, | ||
87 | REG_SPI_RX_TRAINING = 0x1c04, | ||
88 | REG_SPI_RX_CALENDAR = 0x1c08, | ||
89 | REG_SPI_TX_SYNC = 0x1c0c | ||
90 | }; | ||
91 | |||
92 | enum { /* RMON registers */ | ||
93 | REG_RxOctetsTotalOK = 0x80, | ||
94 | REG_RxOctetsBad = 0x84, | ||
95 | REG_RxUCPkts = 0x88, | ||
96 | REG_RxMCPkts = 0x8c, | ||
97 | REG_RxBCPkts = 0x90, | ||
98 | REG_RxJumboPkts = 0xac, | ||
99 | REG_RxFCSErrors = 0xb0, | ||
100 | REG_RxDataErrors = 0xb8, | ||
101 | REG_RxAlignErrors = 0xbc, | ||
102 | REG_RxLongErrors = 0xc0, | ||
103 | REG_RxJabberErrors = 0xc4, | ||
104 | REG_RxPauseMacControlCounter = 0xc8, | ||
105 | REG_RxVeryLongErrors = 0xd0, | ||
106 | REG_RxRuntErrors = 0xd4, | ||
107 | REG_RxShortErrors = 0xd8, | ||
108 | REG_RxSequenceErrors = 0xe0, | ||
109 | REG_RxSymbolErrors = 0xe4, | ||
110 | |||
111 | REG_TxOctetsTotalOK = 0x100, | ||
112 | REG_TxOctetsBad = 0x104, | ||
113 | REG_TxUCPkts = 0x108, | ||
114 | REG_TxMCPkts = 0x10c, | ||
115 | REG_TxBCPkts = 0x110, | ||
116 | REG_TxJumboPkts = 0x12C, | ||
117 | REG_TxTotalCollisions = 0x134, | ||
118 | REG_TxExcessiveLengthDrop = 0x14c, | ||
119 | REG_TxUnderrun = 0x150, | ||
120 | REG_TxCRCErrors = 0x158, | ||
121 | REG_TxPauseFrames = 0x15c | ||
122 | }; | ||
123 | |||
124 | enum { | ||
125 | DIVERSE_CONFIG_PAD_ENABLE = 0x80, | ||
126 | DIVERSE_CONFIG_CRC_ADD = 0x40 | ||
127 | }; | ||
128 | |||
129 | #define MACREG_BASE 0 | ||
130 | #define MACREG(mac, mac_reg) ((mac)->instance->mac_base + (mac_reg)) | ||
131 | |||
132 | struct _cmac_instance { | ||
133 | u32 mac_base; | ||
134 | u32 index; | ||
135 | u32 version; | ||
136 | u32 ticks; | ||
137 | }; | ||
138 | |||
139 | static void disable_port(struct cmac *mac) | ||
140 | { | ||
141 | u32 val; | ||
142 | |||
143 | t1_tpi_read(mac->adapter, REG_PORT_ENABLE, &val); | ||
144 | val &= ~(1 << mac->instance->index); | ||
145 | t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val); | ||
146 | } | ||
147 | |||
148 | /* | ||
149 | * Read the current values of the RMON counters and add them to the cumulative | ||
150 | * port statistics. The HW RMON counters are cleared by this operation. | ||
151 | */ | ||
152 | static void port_stats_update(struct cmac *mac) | ||
153 | { | ||
154 | static struct { | ||
155 | unsigned int reg; | ||
156 | unsigned int offset; | ||
157 | } hw_stats[] = { | ||
158 | |||
159 | #define HW_STAT(name, stat_name) \ | ||
160 | { REG_##name, \ | ||
161 | (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL } | ||
162 | |||
163 | /* Rx stats */ | ||
164 | HW_STAT(RxOctetsTotalOK, RxOctetsOK), | ||
165 | HW_STAT(RxOctetsBad, RxOctetsBad), | ||
166 | HW_STAT(RxUCPkts, RxUnicastFramesOK), | ||
167 | HW_STAT(RxMCPkts, RxMulticastFramesOK), | ||
168 | HW_STAT(RxBCPkts, RxBroadcastFramesOK), | ||
169 | HW_STAT(RxJumboPkts, RxJumboFramesOK), | ||
170 | HW_STAT(RxFCSErrors, RxFCSErrors), | ||
171 | HW_STAT(RxAlignErrors, RxAlignErrors), | ||
172 | HW_STAT(RxLongErrors, RxFrameTooLongErrors), | ||
173 | HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors), | ||
174 | HW_STAT(RxPauseMacControlCounter, RxPauseFrames), | ||
175 | HW_STAT(RxDataErrors, RxDataErrors), | ||
176 | HW_STAT(RxJabberErrors, RxJabberErrors), | ||
177 | HW_STAT(RxRuntErrors, RxRuntErrors), | ||
178 | HW_STAT(RxShortErrors, RxRuntErrors), | ||
179 | HW_STAT(RxSequenceErrors, RxSequenceErrors), | ||
180 | HW_STAT(RxSymbolErrors, RxSymbolErrors), | ||
181 | |||
182 | /* Tx stats (skip collision stats as we are full-duplex only) */ | ||
183 | HW_STAT(TxOctetsTotalOK, TxOctetsOK), | ||
184 | HW_STAT(TxOctetsBad, TxOctetsBad), | ||
185 | HW_STAT(TxUCPkts, TxUnicastFramesOK), | ||
186 | HW_STAT(TxMCPkts, TxMulticastFramesOK), | ||
187 | HW_STAT(TxBCPkts, TxBroadcastFramesOK), | ||
188 | HW_STAT(TxJumboPkts, TxJumboFramesOK), | ||
189 | HW_STAT(TxPauseFrames, TxPauseFrames), | ||
190 | HW_STAT(TxExcessiveLengthDrop, TxLengthErrors), | ||
191 | HW_STAT(TxUnderrun, TxUnderrun), | ||
192 | HW_STAT(TxCRCErrors, TxFCSErrors) | ||
193 | }, *p = hw_stats; | ||
194 | u64 *stats = (u64 *) &mac->stats; | ||
195 | unsigned int i; | ||
196 | |||
197 | for (i = 0; i < ARRAY_SIZE(hw_stats); i++) { | ||
198 | u32 val; | ||
199 | |||
200 | t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val); | ||
201 | stats[p->offset] += val; | ||
202 | } | ||
203 | } | ||
204 | |||
205 | /* No-op interrupt operation as this MAC does not support interrupts */ | ||
206 | static int mac_intr_op(struct cmac *mac) | ||
207 | { | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | /* Expect MAC address to be in network byte order. */ | ||
212 | static int mac_set_address(struct cmac *mac, u8 addr[6]) | ||
213 | { | ||
214 | u32 addr_lo, addr_hi; | ||
215 | |||
216 | addr_lo = addr[2]; | ||
217 | addr_lo = (addr_lo << 8) | addr[3]; | ||
218 | addr_lo = (addr_lo << 8) | addr[4]; | ||
219 | addr_lo = (addr_lo << 8) | addr[5]; | ||
220 | |||
221 | addr_hi = addr[0]; | ||
222 | addr_hi = (addr_hi << 8) | addr[1]; | ||
223 | |||
224 | t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_LOW), addr_lo); | ||
225 | t1_tpi_write(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), addr_hi); | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int mac_get_address(struct cmac *mac, u8 addr[6]) | ||
230 | { | ||
231 | u32 addr_lo, addr_hi; | ||
232 | |||
233 | t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_LOW), &addr_lo); | ||
234 | t1_tpi_read(mac->adapter, MACREG(mac, REG_MACADDR_HIGH), &addr_hi); | ||
235 | |||
236 | addr[0] = (u8) (addr_hi >> 8); | ||
237 | addr[1] = (u8) addr_hi; | ||
238 | addr[2] = (u8) (addr_lo >> 24); | ||
239 | addr[3] = (u8) (addr_lo >> 16); | ||
240 | addr[4] = (u8) (addr_lo >> 8); | ||
241 | addr[5] = (u8) addr_lo; | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | /* This is intended to reset a port, not the whole MAC */ | ||
246 | static int mac_reset(struct cmac *mac) | ||
247 | { | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm) | ||
252 | { | ||
253 | u32 val, new_mode; | ||
254 | adapter_t *adapter = mac->adapter; | ||
255 | u32 addr_lo, addr_hi; | ||
256 | u8 *addr; | ||
257 | |||
258 | t1_tpi_read(adapter, MACREG(mac, REG_RX_FILTER), &val); | ||
259 | new_mode = val & ~7; | ||
260 | if (!t1_rx_mode_promisc(rm) && mac->instance->version > 0) | ||
261 | new_mode |= 1; /* only set if version > 0 due to erratum */ | ||
262 | if (!t1_rx_mode_promisc(rm) && !t1_rx_mode_allmulti(rm) | ||
263 | && t1_rx_mode_mc_cnt(rm) <= 1) | ||
264 | new_mode |= 2; | ||
265 | if (new_mode != val) | ||
266 | t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), new_mode); | ||
267 | switch (t1_rx_mode_mc_cnt(rm)) { | ||
268 | case 0: | ||
269 | t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), 0); | ||
270 | t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), 0); | ||
271 | break; | ||
272 | case 1: | ||
273 | addr = t1_get_next_mcaddr(rm); | ||
274 | addr_lo = (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) | | ||
275 | addr[5]; | ||
276 | addr_hi = (addr[0] << 8) | addr[1]; | ||
277 | t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_LOW), addr_lo); | ||
278 | t1_tpi_write(adapter, MACREG(mac, REG_MC_ADDR_HIGH), addr_hi); | ||
279 | break; | ||
280 | default: | ||
281 | break; | ||
282 | } | ||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | static int mac_set_mtu(struct cmac *mac, int mtu) | ||
287 | { | ||
288 | /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */ | ||
289 | if (mtu > (MAX_FRAME_SIZE - 14 - 4)) | ||
290 | return -EINVAL; | ||
291 | t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE), | ||
292 | mtu + 14 + 4); | ||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static int mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, | ||
297 | int fc) | ||
298 | { | ||
299 | u32 val; | ||
300 | |||
301 | if (speed >= 0 && speed != SPEED_100 && speed != SPEED_1000) | ||
302 | return -1; | ||
303 | if (duplex >= 0 && duplex != DUPLEX_FULL) | ||
304 | return -1; | ||
305 | |||
306 | if (speed >= 0) { | ||
307 | val = speed == SPEED_100 ? 1 : 2; | ||
308 | t1_tpi_write(mac->adapter, MACREG(mac, REG_RGMII_SPEED), val); | ||
309 | } | ||
310 | |||
311 | t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val); | ||
312 | val &= ~3; | ||
313 | if (fc & PAUSE_RX) | ||
314 | val |= 1; | ||
315 | if (fc & PAUSE_TX) | ||
316 | val |= 2; | ||
317 | t1_tpi_write(mac->adapter, MACREG(mac, REG_FC_ENABLE), val); | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int mac_get_speed_duplex_fc(struct cmac *mac, int *speed, int *duplex, | ||
322 | int *fc) | ||
323 | { | ||
324 | u32 val; | ||
325 | |||
326 | if (duplex) | ||
327 | *duplex = DUPLEX_FULL; | ||
328 | if (speed) { | ||
329 | t1_tpi_read(mac->adapter, MACREG(mac, REG_RGMII_SPEED), | ||
330 | &val); | ||
331 | *speed = (val & 2) ? SPEED_1000 : SPEED_100; | ||
332 | } | ||
333 | if (fc) { | ||
334 | t1_tpi_read(mac->adapter, MACREG(mac, REG_FC_ENABLE), &val); | ||
335 | *fc = 0; | ||
336 | if (val & 1) | ||
337 | *fc |= PAUSE_RX; | ||
338 | if (val & 2) | ||
339 | *fc |= PAUSE_TX; | ||
340 | } | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | static void enable_port(struct cmac *mac) | ||
345 | { | ||
346 | u32 val; | ||
347 | u32 index = mac->instance->index; | ||
348 | adapter_t *adapter = mac->adapter; | ||
349 | |||
350 | t1_tpi_read(adapter, MACREG(mac, REG_DIVERSE_CONFIG), &val); | ||
351 | val |= DIVERSE_CONFIG_CRC_ADD | DIVERSE_CONFIG_PAD_ENABLE; | ||
352 | t1_tpi_write(adapter, MACREG(mac, REG_DIVERSE_CONFIG), val); | ||
353 | if (mac->instance->version > 0) | ||
354 | t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 3); | ||
355 | else /* Don't enable unicast address filtering due to IXF1010 bug */ | ||
356 | t1_tpi_write(adapter, MACREG(mac, REG_RX_FILTER), 2); | ||
357 | |||
358 | t1_tpi_read(adapter, REG_RX_ERR_DROP, &val); | ||
359 | val |= (1 << index); | ||
360 | t1_tpi_write(adapter, REG_RX_ERR_DROP, val); | ||
361 | |||
362 | /* | ||
363 | * Clear the port RMON registers by adding their current values to the | ||
364 | * cumulatice port stats and then clearing the stats. Really. | ||
365 | */ | ||
366 | port_stats_update(mac); | ||
367 | memset(&mac->stats, 0, sizeof(struct cmac_statistics)); | ||
368 | mac->instance->ticks = 0; | ||
369 | |||
370 | t1_tpi_read(adapter, REG_PORT_ENABLE, &val); | ||
371 | val |= (1 << index); | ||
372 | t1_tpi_write(adapter, REG_PORT_ENABLE, val); | ||
373 | |||
374 | index <<= 2; | ||
375 | if (is_T2(adapter)) { | ||
376 | /* T204: set the Fifo water level & threshold */ | ||
377 | t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740); | ||
378 | t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730); | ||
379 | t1_tpi_write(adapter, TX_FIFO_HIGH_WATERMARK_BASE + index, 0x600); | ||
380 | t1_tpi_write(adapter, TX_FIFO_LOW_WATERMARK_BASE + index, 0x1d0); | ||
381 | t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x1100); | ||
382 | } else { | ||
383 | /* | ||
384 | * Set the TX Fifo Threshold to 0x400 instead of 0x100 to work around | ||
385 | * Underrun problem. Intel has blessed this solution. | ||
386 | */ | ||
387 | t1_tpi_write(adapter, TX_FIFO_XFER_THRES_BASE + index, 0x400); | ||
388 | } | ||
389 | } | ||
390 | |||
391 | /* IXF1010 ports do not have separate enables for TX and RX */ | ||
392 | static int mac_enable(struct cmac *mac, int which) | ||
393 | { | ||
394 | if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX)) | ||
395 | enable_port(mac); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int mac_disable(struct cmac *mac, int which) | ||
400 | { | ||
401 | if (which & (MAC_DIRECTION_RX | MAC_DIRECTION_TX)) | ||
402 | disable_port(mac); | ||
403 | return 0; | ||
404 | } | ||
405 | |||
406 | #define RMON_UPDATE(mac, name, stat_name) \ | ||
407 | t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \ | ||
408 | (mac)->stats.stat_name += val; | ||
409 | |||
410 | /* | ||
411 | * This function is called periodically to accumulate the current values of the | ||
412 | * RMON counters into the port statistics. Since the counters are only 32 bits | ||
413 | * some of them can overflow in less than a minute at GigE speeds, so this | ||
414 | * function should be called every 30 seconds or so. | ||
415 | * | ||
416 | * To cut down on reading costs we update only the octet counters at each tick | ||
417 | * and do a full update at major ticks, which can be every 30 minutes or more. | ||
418 | */ | ||
419 | static const struct cmac_statistics *mac_update_statistics(struct cmac *mac, | ||
420 | int flag) | ||
421 | { | ||
422 | if (flag == MAC_STATS_UPDATE_FULL || | ||
423 | MAJOR_UPDATE_TICKS <= mac->instance->ticks) { | ||
424 | port_stats_update(mac); | ||
425 | mac->instance->ticks = 0; | ||
426 | } else { | ||
427 | u32 val; | ||
428 | |||
429 | RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK); | ||
430 | RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK); | ||
431 | mac->instance->ticks++; | ||
432 | } | ||
433 | return &mac->stats; | ||
434 | } | ||
435 | |||
436 | static void mac_destroy(struct cmac *mac) | ||
437 | { | ||
438 | kfree(mac); | ||
439 | } | ||
440 | |||
441 | static struct cmac_ops ixf1010_ops = { | ||
442 | .destroy = mac_destroy, | ||
443 | .reset = mac_reset, | ||
444 | .interrupt_enable = mac_intr_op, | ||
445 | .interrupt_disable = mac_intr_op, | ||
446 | .interrupt_clear = mac_intr_op, | ||
447 | .enable = mac_enable, | ||
448 | .disable = mac_disable, | ||
449 | .set_mtu = mac_set_mtu, | ||
450 | .set_rx_mode = mac_set_rx_mode, | ||
451 | .set_speed_duplex_fc = mac_set_speed_duplex_fc, | ||
452 | .get_speed_duplex_fc = mac_get_speed_duplex_fc, | ||
453 | .statistics_update = mac_update_statistics, | ||
454 | .macaddress_get = mac_get_address, | ||
455 | .macaddress_set = mac_set_address, | ||
456 | }; | ||
457 | |||
458 | static int ixf1010_mac_reset(adapter_t *adapter) | ||
459 | { | ||
460 | u32 val; | ||
461 | |||
462 | t1_tpi_read(adapter, A_ELMER0_GPO, &val); | ||
463 | if ((val & 1) != 0) { | ||
464 | val &= ~1; | ||
465 | t1_tpi_write(adapter, A_ELMER0_GPO, val); | ||
466 | udelay(2); | ||
467 | } | ||
468 | val |= 1; | ||
469 | t1_tpi_write(adapter, A_ELMER0_GPO, val); | ||
470 | udelay(2); | ||
471 | |||
472 | t1_tpi_write(adapter, REG_PORT_ENABLE, 0); | ||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index) | ||
477 | { | ||
478 | struct cmac *mac; | ||
479 | u32 val; | ||
480 | |||
481 | if (index > 9) | ||
482 | return NULL; | ||
483 | |||
484 | mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL); | ||
485 | if (!mac) | ||
486 | return NULL; | ||
487 | |||
488 | mac->ops = &ixf1010_ops; | ||
489 | mac->instance = (cmac_instance *)(mac + 1); | ||
490 | |||
491 | mac->instance->mac_base = MACREG_BASE + (index * 0x200); | ||
492 | mac->instance->index = index; | ||
493 | mac->adapter = adapter; | ||
494 | mac->instance->ticks = 0; | ||
495 | |||
496 | t1_tpi_read(adapter, REG_JTAG_ID, &val); | ||
497 | mac->instance->version = val >> 28; | ||
498 | return mac; | ||
499 | } | ||
500 | |||
501 | struct gmac t1_ixf1010_ops = { | ||
502 | STATS_TICK_SECS, | ||
503 | ixf1010_mac_create, | ||
504 | ixf1010_mac_reset | ||
505 | }; | ||
diff --git a/drivers/net/chelsio/mac.c b/drivers/net/chelsio/mac.c index 6af39dc70459..1d972825eac3 100644 --- a/drivers/net/chelsio/mac.c +++ b/drivers/net/chelsio/mac.c | |||
@@ -363,6 +363,6 @@ static struct cmac *mac_create(adapter_t *adapter, int index) | |||
363 | return mac; | 363 | return mac; |
364 | } | 364 | } |
365 | 365 | ||
366 | struct gmac t1_chelsio_mac_ops = { | 366 | const struct gmac t1_chelsio_mac_ops = { |
367 | .create = mac_create | 367 | .create = mac_create |
368 | }; | 368 | }; |
diff --git a/drivers/net/chelsio/mv88e1xxx.c b/drivers/net/chelsio/mv88e1xxx.c index 5867e3b0a887..0632be0d6494 100644 --- a/drivers/net/chelsio/mv88e1xxx.c +++ b/drivers/net/chelsio/mv88e1xxx.c | |||
@@ -354,7 +354,7 @@ static struct cphy_ops mv88e1xxx_ops = { | |||
354 | }; | 354 | }; |
355 | 355 | ||
356 | static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr, | 356 | static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr, |
357 | struct mdio_ops *mdio_ops) | 357 | const struct mdio_ops *mdio_ops) |
358 | { | 358 | { |
359 | struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); | 359 | struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); |
360 | 360 | ||
@@ -390,7 +390,7 @@ static int mv88e1xxx_phy_reset(adapter_t* adapter) | |||
390 | return 0; | 390 | return 0; |
391 | } | 391 | } |
392 | 392 | ||
393 | struct gphy t1_mv88e1xxx_ops = { | 393 | const struct gphy t1_mv88e1xxx_ops = { |
394 | mv88e1xxx_phy_create, | 394 | .create = mv88e1xxx_phy_create, |
395 | mv88e1xxx_phy_reset | 395 | .reset = mv88e1xxx_phy_reset |
396 | }; | 396 | }; |
diff --git a/drivers/net/chelsio/mv88x201x.c b/drivers/net/chelsio/mv88x201x.c index c8e89480d906..cd856041af34 100644 --- a/drivers/net/chelsio/mv88x201x.c +++ b/drivers/net/chelsio/mv88x201x.c | |||
@@ -208,7 +208,7 @@ static struct cphy_ops mv88x201x_ops = { | |||
208 | }; | 208 | }; |
209 | 209 | ||
210 | static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, | 210 | static struct cphy *mv88x201x_phy_create(adapter_t *adapter, int phy_addr, |
211 | struct mdio_ops *mdio_ops) | 211 | const struct mdio_ops *mdio_ops) |
212 | { | 212 | { |
213 | u32 val; | 213 | u32 val; |
214 | struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); | 214 | struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); |
@@ -252,7 +252,7 @@ static int mv88x201x_phy_reset(adapter_t *adapter) | |||
252 | return 0; | 252 | return 0; |
253 | } | 253 | } |
254 | 254 | ||
255 | struct gphy t1_mv88x201x_ops = { | 255 | const struct gphy t1_mv88x201x_ops = { |
256 | mv88x201x_phy_create, | 256 | .create = mv88x201x_phy_create, |
257 | mv88x201x_phy_reset | 257 | .reset = mv88x201x_phy_reset |
258 | }; | 258 | }; |
diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 87dde3e60046..040acd29995a 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c | |||
@@ -166,7 +166,7 @@ static struct cphy_ops my3126_ops = { | |||
166 | }; | 166 | }; |
167 | 167 | ||
168 | static struct cphy *my3126_phy_create(adapter_t *adapter, | 168 | static struct cphy *my3126_phy_create(adapter_t *adapter, |
169 | int phy_addr, struct mdio_ops *mdio_ops) | 169 | int phy_addr, const struct mdio_ops *mdio_ops) |
170 | { | 170 | { |
171 | struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); | 171 | struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); |
172 | 172 | ||
@@ -201,7 +201,7 @@ static int my3126_phy_reset(adapter_t * adapter) | |||
201 | return 0; | 201 | return 0; |
202 | } | 202 | } |
203 | 203 | ||
204 | struct gphy t1_my3126_ops = { | 204 | const struct gphy t1_my3126_ops = { |
205 | my3126_phy_create, | 205 | .create = my3126_phy_create, |
206 | my3126_phy_reset | 206 | .reset = my3126_phy_reset |
207 | }; | 207 | }; |
diff --git a/drivers/net/chelsio/pm3393.c b/drivers/net/chelsio/pm3393.c index 69129edeefd6..678778a8d133 100644 --- a/drivers/net/chelsio/pm3393.c +++ b/drivers/net/chelsio/pm3393.c | |||
@@ -807,8 +807,8 @@ static int pm3393_mac_reset(adapter_t * adapter) | |||
807 | return successful_reset ? 0 : 1; | 807 | return successful_reset ? 0 : 1; |
808 | } | 808 | } |
809 | 809 | ||
810 | struct gmac t1_pm3393_ops = { | 810 | const struct gmac t1_pm3393_ops = { |
811 | STATS_TICK_SECS, | 811 | .stats_update_period = STATS_TICK_SECS, |
812 | pm3393_mac_create, | 812 | .create = pm3393_mac_create, |
813 | pm3393_mac_reset | 813 | .reset = pm3393_mac_reset, |
814 | }; | 814 | }; |
diff --git a/drivers/net/chelsio/subr.c b/drivers/net/chelsio/subr.c index c2522cdfab37..7de9a611e1f7 100644 --- a/drivers/net/chelsio/subr.c +++ b/drivers/net/chelsio/subr.c | |||
@@ -321,10 +321,10 @@ static int mi1_mdio_write(adapter_t *adapter, int phy_addr, int mmd_addr, | |||
321 | } | 321 | } |
322 | 322 | ||
323 | #if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR) | 323 | #if defined(CONFIG_CHELSIO_T1_1G) || defined(CONFIG_CHELSIO_T1_COUGAR) |
324 | static struct mdio_ops mi1_mdio_ops = { | 324 | static const struct mdio_ops mi1_mdio_ops = { |
325 | mi1_mdio_init, | 325 | .init = mi1_mdio_init, |
326 | mi1_mdio_read, | 326 | .read = mi1_mdio_read, |
327 | mi1_mdio_write | 327 | .write = mi1_mdio_write |
328 | }; | 328 | }; |
329 | #endif | 329 | #endif |
330 | 330 | ||
@@ -377,10 +377,10 @@ static int mi1_mdio_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr, | |||
377 | return 0; | 377 | return 0; |
378 | } | 378 | } |
379 | 379 | ||
380 | static struct mdio_ops mi1_mdio_ext_ops = { | 380 | static const struct mdio_ops mi1_mdio_ext_ops = { |
381 | mi1_mdio_init, | 381 | .init = mi1_mdio_init, |
382 | mi1_mdio_ext_read, | 382 | .read = mi1_mdio_ext_read, |
383 | mi1_mdio_ext_write | 383 | .write = mi1_mdio_ext_write |
384 | }; | 384 | }; |
385 | 385 | ||
386 | enum { | 386 | enum { |
@@ -392,63 +392,136 @@ enum { | |||
392 | CH_BRD_N204_4CU, | 392 | CH_BRD_N204_4CU, |
393 | }; | 393 | }; |
394 | 394 | ||
395 | static struct board_info t1_board[] = { | 395 | static const struct board_info t1_board[] = { |
396 | 396 | { | |
397 | { CHBT_BOARD_CHT110, 1/*ports#*/, | 397 | .board = CHBT_BOARD_CHT110, |
398 | SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T1, | 398 | .port_number = 1, |
399 | CHBT_MAC_PM3393, CHBT_PHY_MY3126, | 399 | .caps = SUPPORTED_10000baseT_Full, |
400 | 125000000/*clk-core*/, 150000000/*clk-mc3*/, 125000000/*clk-mc4*/, | 400 | .chip_term = CHBT_TERM_T1, |
401 | 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/, | 401 | .chip_mac = CHBT_MAC_PM3393, |
402 | 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops, | 402 | .chip_phy = CHBT_PHY_MY3126, |
403 | &t1_my3126_ops, &mi1_mdio_ext_ops, | 403 | .clock_core = 125000000, |
404 | "Chelsio T110 1x10GBase-CX4 TOE" }, | 404 | .clock_mc3 = 150000000, |
405 | 405 | .clock_mc4 = 125000000, | |
406 | { CHBT_BOARD_N110, 1/*ports#*/, | 406 | .espi_nports = 1, |
407 | SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T1, | 407 | .clock_elmer0 = 44, |
408 | CHBT_MAC_PM3393, CHBT_PHY_88X2010, | 408 | .mdio_mdien = 1, |
409 | 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, | 409 | .mdio_mdiinv = 1, |
410 | 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, | 410 | .mdio_mdc = 1, |
411 | 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, | 411 | .mdio_phybaseaddr = 1, |
412 | &t1_mv88x201x_ops, &mi1_mdio_ext_ops, | 412 | .gmac = &t1_pm3393_ops, |
413 | "Chelsio N110 1x10GBaseX NIC" }, | 413 | .gphy = &t1_my3126_ops, |
414 | 414 | .mdio_ops = &mi1_mdio_ext_ops, | |
415 | { CHBT_BOARD_N210, 1/*ports#*/, | 415 | .desc = "Chelsio T110 1x10GBase-CX4 TOE", |
416 | SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE /*caps*/, CHBT_TERM_T2, | 416 | }, |
417 | CHBT_MAC_PM3393, CHBT_PHY_88X2010, | 417 | |
418 | 125000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, | 418 | { |
419 | 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, | 419 | .board = CHBT_BOARD_N110, |
420 | 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, | 420 | .port_number = 1, |
421 | &t1_mv88x201x_ops, &mi1_mdio_ext_ops, | 421 | .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, |
422 | "Chelsio N210 1x10GBaseX NIC" }, | 422 | .chip_term = CHBT_TERM_T1, |
423 | 423 | .chip_mac = CHBT_MAC_PM3393, | |
424 | { CHBT_BOARD_CHT210, 1/*ports#*/, | 424 | .chip_phy = CHBT_PHY_88X2010, |
425 | SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2, | 425 | .clock_core = 125000000, |
426 | CHBT_MAC_PM3393, CHBT_PHY_88X2010, | 426 | .espi_nports = 1, |
427 | 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/, | 427 | .clock_elmer0 = 44, |
428 | 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, | 428 | .mdio_mdien = 0, |
429 | 0/*mdiinv*/, 1/*mdc*/, 0/*phybaseaddr*/, &t1_pm3393_ops, | 429 | .mdio_mdiinv = 0, |
430 | &t1_mv88x201x_ops, &mi1_mdio_ext_ops, | 430 | .mdio_mdc = 1, |
431 | "Chelsio T210 1x10GBaseX TOE" }, | 431 | .mdio_phybaseaddr = 0, |
432 | 432 | .gmac = &t1_pm3393_ops, | |
433 | { CHBT_BOARD_CHT210, 1/*ports#*/, | 433 | .gphy = &t1_mv88x201x_ops, |
434 | SUPPORTED_10000baseT_Full /*caps*/, CHBT_TERM_T2, | 434 | .mdio_ops = &mi1_mdio_ext_ops, |
435 | CHBT_MAC_PM3393, CHBT_PHY_MY3126, | 435 | .desc = "Chelsio N110 1x10GBaseX NIC", |
436 | 125000000/*clk-core*/, 133000000/*clk-mc3*/, 125000000/*clk-mc4*/, | 436 | }, |
437 | 1/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 1/*mdien*/, | 437 | |
438 | 1/*mdiinv*/, 1/*mdc*/, 1/*phybaseaddr*/, &t1_pm3393_ops, | 438 | { |
439 | &t1_my3126_ops, &mi1_mdio_ext_ops, | 439 | .board = CHBT_BOARD_N210, |
440 | "Chelsio T210 1x10GBase-CX4 TOE" }, | 440 | .port_number = 1, |
441 | .caps = SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE, | ||
442 | .chip_term = CHBT_TERM_T2, | ||
443 | .chip_mac = CHBT_MAC_PM3393, | ||
444 | .chip_phy = CHBT_PHY_88X2010, | ||
445 | .clock_core = 125000000, | ||
446 | .espi_nports = 1, | ||
447 | .clock_elmer0 = 44, | ||
448 | .mdio_mdien = 0, | ||
449 | .mdio_mdiinv = 0, | ||
450 | .mdio_mdc = 1, | ||
451 | .mdio_phybaseaddr = 0, | ||
452 | .gmac = &t1_pm3393_ops, | ||
453 | .gphy = &t1_mv88x201x_ops, | ||
454 | .mdio_ops = &mi1_mdio_ext_ops, | ||
455 | .desc = "Chelsio N210 1x10GBaseX NIC", | ||
456 | }, | ||
457 | |||
458 | { | ||
459 | .board = CHBT_BOARD_CHT210, | ||
460 | .port_number = 1, | ||
461 | .caps = SUPPORTED_10000baseT_Full, | ||
462 | .chip_term = CHBT_TERM_T2, | ||
463 | .chip_mac = CHBT_MAC_PM3393, | ||
464 | .chip_phy = CHBT_PHY_88X2010, | ||
465 | .clock_core = 125000000, | ||
466 | .clock_mc3 = 133000000, | ||
467 | .clock_mc4 = 125000000, | ||
468 | .espi_nports = 1, | ||
469 | .clock_elmer0 = 44, | ||
470 | .mdio_mdien = 0, | ||
471 | .mdio_mdiinv = 0, | ||
472 | .mdio_mdc = 1, | ||
473 | .mdio_phybaseaddr = 0, | ||
474 | .gmac = &t1_pm3393_ops, | ||
475 | .gphy = &t1_mv88x201x_ops, | ||
476 | .mdio_ops = &mi1_mdio_ext_ops, | ||
477 | .desc = "Chelsio T210 1x10GBaseX TOE", | ||
478 | }, | ||
479 | |||
480 | { | ||
481 | .board = CHBT_BOARD_CHT210, | ||
482 | .port_number = 1, | ||
483 | .caps = SUPPORTED_10000baseT_Full, | ||
484 | .chip_term = CHBT_TERM_T2, | ||
485 | .chip_mac = CHBT_MAC_PM3393, | ||
486 | .chip_phy = CHBT_PHY_MY3126, | ||
487 | .clock_core = 125000000, | ||
488 | .clock_mc3 = 133000000, | ||
489 | .clock_mc4 = 125000000, | ||
490 | .espi_nports = 1, | ||
491 | .clock_elmer0 = 44, | ||
492 | .mdio_mdien = 1, | ||
493 | .mdio_mdiinv = 1, | ||
494 | .mdio_mdc = 1, | ||
495 | .mdio_phybaseaddr = 1, | ||
496 | .gmac = &t1_pm3393_ops, | ||
497 | .gphy = &t1_my3126_ops, | ||
498 | .mdio_ops = &mi1_mdio_ext_ops, | ||
499 | .desc = "Chelsio T210 1x10GBase-CX4 TOE", | ||
500 | }, | ||
441 | 501 | ||
442 | #ifdef CONFIG_CHELSIO_T1_1G | 502 | #ifdef CONFIG_CHELSIO_T1_1G |
443 | { CHBT_BOARD_CHN204, 4/*ports#*/, | 503 | { |
444 | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | | 504 | .board = CHBT_BOARD_CHN204, |
445 | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | | 505 | .port_number = 4, |
446 | SUPPORTED_PAUSE | SUPPORTED_TP /*caps*/, CHBT_TERM_T2, CHBT_MAC_VSC7321, CHBT_PHY_88E1111, | 506 | .caps = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
447 | 100000000/*clk-core*/, 0/*clk-mc3*/, 0/*clk-mc4*/, | 507 | | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
448 | 4/*espi-ports*/, 0/*clk-cspi*/, 44/*clk-elmer0*/, 0/*mdien*/, | 508 | | SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | |
449 | 0/*mdiinv*/, 1/*mdc*/, 4/*phybaseaddr*/, &t1_vsc7326_ops, | 509 | SUPPORTED_PAUSE | SUPPORTED_TP, |
450 | &t1_mv88e1xxx_ops, &mi1_mdio_ops, | 510 | .chip_term = CHBT_TERM_T2, |
451 | "Chelsio N204 4x100/1000BaseT NIC" }, | 511 | .chip_mac = CHBT_MAC_VSC7321, |
512 | .chip_phy = CHBT_PHY_88E1111, | ||
513 | .clock_core = 100000000, | ||
514 | .espi_nports = 4, | ||
515 | .clock_elmer0 = 44, | ||
516 | .mdio_mdien = 0, | ||
517 | .mdio_mdiinv = 0, | ||
518 | .mdio_mdc = 0, | ||
519 | .mdio_phybaseaddr = 4, | ||
520 | .gmac = &t1_vsc7326_ops, | ||
521 | .gphy = &t1_mv88e1xxx_ops, | ||
522 | .mdio_ops = &mi1_mdio_ops, | ||
523 | .desc = "Chelsio N204 4x100/1000BaseT NIC", | ||
524 | }, | ||
452 | #endif | 525 | #endif |
453 | 526 | ||
454 | }; | 527 | }; |
diff --git a/drivers/net/chelsio/vsc7326.c b/drivers/net/chelsio/vsc7326.c index 534ffa0f616e..99b51f61fe77 100644 --- a/drivers/net/chelsio/vsc7326.c +++ b/drivers/net/chelsio/vsc7326.c | |||
@@ -723,7 +723,7 @@ static int vsc7326_mac_reset(adapter_t *adapter) | |||
723 | return 0; | 723 | return 0; |
724 | } | 724 | } |
725 | 725 | ||
726 | struct gmac t1_vsc7326_ops = { | 726 | const struct gmac t1_vsc7326_ops = { |
727 | .stats_update_period = STATS_TICK_SECS, | 727 | .stats_update_period = STATS_TICK_SECS, |
728 | .create = vsc7326_mac_create, | 728 | .create = vsc7326_mac_create, |
729 | .reset = vsc7326_mac_reset, | 729 | .reset = vsc7326_mac_reset, |
diff --git a/drivers/net/chelsio/vsc8244.c b/drivers/net/chelsio/vsc8244.c deleted file mode 100644 index 251d4859c91d..000000000000 --- a/drivers/net/chelsio/vsc8244.c +++ /dev/null | |||
@@ -1,367 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of the Chelsio T2 Ethernet driver. | ||
3 | * | ||
4 | * Copyright (C) 2005 Chelsio Communications. All rights reserved. | ||
5 | * | ||
6 | * This program is distributed in the hope that it will be useful, but WITHOUT | ||
7 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
8 | * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this | ||
9 | * release for licensing terms and conditions. | ||
10 | */ | ||
11 | |||
12 | #include "common.h" | ||
13 | #include "cphy.h" | ||
14 | #include "elmer0.h" | ||
15 | |||
16 | #ifndef ADVERTISE_PAUSE_CAP | ||
17 | # define ADVERTISE_PAUSE_CAP 0x400 | ||
18 | #endif | ||
19 | #ifndef ADVERTISE_PAUSE_ASYM | ||
20 | # define ADVERTISE_PAUSE_ASYM 0x800 | ||
21 | #endif | ||
22 | |||
23 | /* Gigabit MII registers */ | ||
24 | #ifndef MII_CTRL1000 | ||
25 | # define MII_CTRL1000 9 | ||
26 | #endif | ||
27 | |||
28 | #ifndef ADVERTISE_1000FULL | ||
29 | # define ADVERTISE_1000FULL 0x200 | ||
30 | # define ADVERTISE_1000HALF 0x100 | ||
31 | #endif | ||
32 | |||
33 | /* VSC8244 PHY specific registers. */ | ||
34 | enum { | ||
35 | VSC8244_INTR_ENABLE = 25, | ||
36 | VSC8244_INTR_STATUS = 26, | ||
37 | VSC8244_AUX_CTRL_STAT = 28, | ||
38 | }; | ||
39 | |||
40 | enum { | ||
41 | VSC_INTR_RX_ERR = 1 << 0, | ||
42 | VSC_INTR_MS_ERR = 1 << 1, /* master/slave resolution error */ | ||
43 | VSC_INTR_CABLE = 1 << 2, /* cable impairment */ | ||
44 | VSC_INTR_FALSE_CARR = 1 << 3, /* false carrier */ | ||
45 | VSC_INTR_MEDIA_CHG = 1 << 4, /* AMS media change */ | ||
46 | VSC_INTR_RX_FIFO = 1 << 5, /* Rx FIFO over/underflow */ | ||
47 | VSC_INTR_TX_FIFO = 1 << 6, /* Tx FIFO over/underflow */ | ||
48 | VSC_INTR_DESCRAMBL = 1 << 7, /* descrambler lock-lost */ | ||
49 | VSC_INTR_SYMBOL_ERR = 1 << 8, /* symbol error */ | ||
50 | VSC_INTR_NEG_DONE = 1 << 10, /* autoneg done */ | ||
51 | VSC_INTR_NEG_ERR = 1 << 11, /* autoneg error */ | ||
52 | VSC_INTR_LINK_CHG = 1 << 13, /* link change */ | ||
53 | VSC_INTR_ENABLE = 1 << 15, /* interrupt enable */ | ||
54 | }; | ||
55 | |||
56 | #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \ | ||
57 | VSC_INTR_NEG_DONE) | ||
58 | #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \ | ||
59 | VSC_INTR_ENABLE) | ||
60 | |||
61 | /* PHY specific auxiliary control & status register fields */ | ||
62 | #define S_ACSR_ACTIPHY_TMR 0 | ||
63 | #define M_ACSR_ACTIPHY_TMR 0x3 | ||
64 | #define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR) | ||
65 | |||
66 | #define S_ACSR_SPEED 3 | ||
67 | #define M_ACSR_SPEED 0x3 | ||
68 | #define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED) | ||
69 | |||
70 | #define S_ACSR_DUPLEX 5 | ||
71 | #define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX) | ||
72 | |||
73 | #define S_ACSR_ACTIPHY 6 | ||
74 | #define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY) | ||
75 | |||
76 | /* | ||
77 | * Reset the PHY. This PHY completes reset immediately so we never wait. | ||
78 | */ | ||
79 | static int vsc8244_reset(struct cphy *cphy, int wait) | ||
80 | { | ||
81 | int err; | ||
82 | unsigned int ctl; | ||
83 | |||
84 | err = simple_mdio_read(cphy, MII_BMCR, &ctl); | ||
85 | if (err) | ||
86 | return err; | ||
87 | |||
88 | ctl &= ~BMCR_PDOWN; | ||
89 | ctl |= BMCR_RESET; | ||
90 | return simple_mdio_write(cphy, MII_BMCR, ctl); | ||
91 | } | ||
92 | |||
93 | static int vsc8244_intr_enable(struct cphy *cphy) | ||
94 | { | ||
95 | simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK); | ||
96 | |||
97 | /* Enable interrupts through Elmer */ | ||
98 | if (t1_is_asic(cphy->adapter)) { | ||
99 | u32 elmer; | ||
100 | |||
101 | t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); | ||
102 | elmer |= ELMER0_GP_BIT1; | ||
103 | if (is_T2(cphy->adapter)) | ||
104 | elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; | ||
105 | t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); | ||
106 | } | ||
107 | |||
108 | return 0; | ||
109 | } | ||
110 | |||
111 | static int vsc8244_intr_disable(struct cphy *cphy) | ||
112 | { | ||
113 | simple_mdio_write(cphy, VSC8244_INTR_ENABLE, 0); | ||
114 | |||
115 | if (t1_is_asic(cphy->adapter)) { | ||
116 | u32 elmer; | ||
117 | |||
118 | t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer); | ||
119 | elmer &= ~ELMER0_GP_BIT1; | ||
120 | if (is_T2(cphy->adapter)) | ||
121 | elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4); | ||
122 | t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer); | ||
123 | } | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int vsc8244_intr_clear(struct cphy *cphy) | ||
129 | { | ||
130 | u32 val; | ||
131 | u32 elmer; | ||
132 | |||
133 | /* Clear PHY interrupts by reading the register. */ | ||
134 | simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val); | ||
135 | |||
136 | if (t1_is_asic(cphy->adapter)) { | ||
137 | t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer); | ||
138 | elmer |= ELMER0_GP_BIT1; | ||
139 | if (is_T2(cphy->adapter)) | ||
140 | elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4; | ||
141 | t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer); | ||
142 | } | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Force the PHY speed and duplex. This also disables auto-negotiation, except | ||
149 | * for 1Gb/s, where auto-negotiation is mandatory. | ||
150 | */ | ||
151 | static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex) | ||
152 | { | ||
153 | int err; | ||
154 | unsigned int ctl; | ||
155 | |||
156 | err = simple_mdio_read(phy, MII_BMCR, &ctl); | ||
157 | if (err) | ||
158 | return err; | ||
159 | |||
160 | if (speed >= 0) { | ||
161 | ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); | ||
162 | if (speed == SPEED_100) | ||
163 | ctl |= BMCR_SPEED100; | ||
164 | else if (speed == SPEED_1000) | ||
165 | ctl |= BMCR_SPEED1000; | ||
166 | } | ||
167 | if (duplex >= 0) { | ||
168 | ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE); | ||
169 | if (duplex == DUPLEX_FULL) | ||
170 | ctl |= BMCR_FULLDPLX; | ||
171 | } | ||
172 | if (ctl & BMCR_SPEED1000) /* auto-negotiation required for 1Gb/s */ | ||
173 | ctl |= BMCR_ANENABLE; | ||
174 | return simple_mdio_write(phy, MII_BMCR, ctl); | ||
175 | } | ||
176 | |||
177 | int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits) | ||
178 | { | ||
179 | int ret; | ||
180 | unsigned int val; | ||
181 | |||
182 | ret = mdio_read(phy, mmd, reg, &val); | ||
183 | if (!ret) | ||
184 | ret = mdio_write(phy, mmd, reg, val | bits); | ||
185 | return ret; | ||
186 | } | ||
187 | |||
188 | static int vsc8244_autoneg_enable(struct cphy *cphy) | ||
189 | { | ||
190 | return t1_mdio_set_bits(cphy, 0, MII_BMCR, | ||
191 | BMCR_ANENABLE | BMCR_ANRESTART); | ||
192 | } | ||
193 | |||
194 | static int vsc8244_autoneg_restart(struct cphy *cphy) | ||
195 | { | ||
196 | return t1_mdio_set_bits(cphy, 0, MII_BMCR, BMCR_ANRESTART); | ||
197 | } | ||
198 | |||
199 | static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map) | ||
200 | { | ||
201 | int err; | ||
202 | unsigned int val = 0; | ||
203 | |||
204 | err = simple_mdio_read(phy, MII_CTRL1000, &val); | ||
205 | if (err) | ||
206 | return err; | ||
207 | |||
208 | val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL); | ||
209 | if (advertise_map & ADVERTISED_1000baseT_Half) | ||
210 | val |= ADVERTISE_1000HALF; | ||
211 | if (advertise_map & ADVERTISED_1000baseT_Full) | ||
212 | val |= ADVERTISE_1000FULL; | ||
213 | |||
214 | err = simple_mdio_write(phy, MII_CTRL1000, val); | ||
215 | if (err) | ||
216 | return err; | ||
217 | |||
218 | val = 1; | ||
219 | if (advertise_map & ADVERTISED_10baseT_Half) | ||
220 | val |= ADVERTISE_10HALF; | ||
221 | if (advertise_map & ADVERTISED_10baseT_Full) | ||
222 | val |= ADVERTISE_10FULL; | ||
223 | if (advertise_map & ADVERTISED_100baseT_Half) | ||
224 | val |= ADVERTISE_100HALF; | ||
225 | if (advertise_map & ADVERTISED_100baseT_Full) | ||
226 | val |= ADVERTISE_100FULL; | ||
227 | if (advertise_map & ADVERTISED_PAUSE) | ||
228 | val |= ADVERTISE_PAUSE_CAP; | ||
229 | if (advertise_map & ADVERTISED_ASYM_PAUSE) | ||
230 | val |= ADVERTISE_PAUSE_ASYM; | ||
231 | return simple_mdio_write(phy, MII_ADVERTISE, val); | ||
232 | } | ||
233 | |||
234 | static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok, | ||
235 | int *speed, int *duplex, int *fc) | ||
236 | { | ||
237 | unsigned int bmcr, status, lpa, adv; | ||
238 | int err, sp = -1, dplx = -1, pause = 0; | ||
239 | |||
240 | err = simple_mdio_read(cphy, MII_BMCR, &bmcr); | ||
241 | if (!err) | ||
242 | err = simple_mdio_read(cphy, MII_BMSR, &status); | ||
243 | if (err) | ||
244 | return err; | ||
245 | |||
246 | if (link_ok) { | ||
247 | /* | ||
248 | * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it | ||
249 | * once more to get the current link state. | ||
250 | */ | ||
251 | if (!(status & BMSR_LSTATUS)) | ||
252 | err = simple_mdio_read(cphy, MII_BMSR, &status); | ||
253 | if (err) | ||
254 | return err; | ||
255 | *link_ok = (status & BMSR_LSTATUS) != 0; | ||
256 | } | ||
257 | if (!(bmcr & BMCR_ANENABLE)) { | ||
258 | dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF; | ||
259 | if (bmcr & BMCR_SPEED1000) | ||
260 | sp = SPEED_1000; | ||
261 | else if (bmcr & BMCR_SPEED100) | ||
262 | sp = SPEED_100; | ||
263 | else | ||
264 | sp = SPEED_10; | ||
265 | } else if (status & BMSR_ANEGCOMPLETE) { | ||
266 | err = simple_mdio_read(cphy, VSC8244_AUX_CTRL_STAT, &status); | ||
267 | if (err) | ||
268 | return err; | ||
269 | |||
270 | dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF; | ||
271 | sp = G_ACSR_SPEED(status); | ||
272 | if (sp == 0) | ||
273 | sp = SPEED_10; | ||
274 | else if (sp == 1) | ||
275 | sp = SPEED_100; | ||
276 | else | ||
277 | sp = SPEED_1000; | ||
278 | |||
279 | if (fc && dplx == DUPLEX_FULL) { | ||
280 | err = simple_mdio_read(cphy, MII_LPA, &lpa); | ||
281 | if (!err) | ||
282 | err = simple_mdio_read(cphy, MII_ADVERTISE, | ||
283 | &adv); | ||
284 | if (err) | ||
285 | return err; | ||
286 | |||
287 | if (lpa & adv & ADVERTISE_PAUSE_CAP) | ||
288 | pause = PAUSE_RX | PAUSE_TX; | ||
289 | else if ((lpa & ADVERTISE_PAUSE_CAP) && | ||
290 | (lpa & ADVERTISE_PAUSE_ASYM) && | ||
291 | (adv & ADVERTISE_PAUSE_ASYM)) | ||
292 | pause = PAUSE_TX; | ||
293 | else if ((lpa & ADVERTISE_PAUSE_ASYM) && | ||
294 | (adv & ADVERTISE_PAUSE_CAP)) | ||
295 | pause = PAUSE_RX; | ||
296 | } | ||
297 | } | ||
298 | if (speed) | ||
299 | *speed = sp; | ||
300 | if (duplex) | ||
301 | *duplex = dplx; | ||
302 | if (fc) | ||
303 | *fc = pause; | ||
304 | return 0; | ||
305 | } | ||
306 | |||
307 | static int vsc8244_intr_handler(struct cphy *cphy) | ||
308 | { | ||
309 | unsigned int cause; | ||
310 | int err, cphy_cause = 0; | ||
311 | |||
312 | err = simple_mdio_read(cphy, VSC8244_INTR_STATUS, &cause); | ||
313 | if (err) | ||
314 | return err; | ||
315 | |||
316 | cause &= INTR_MASK; | ||
317 | if (cause & CFG_CHG_INTR_MASK) | ||
318 | cphy_cause |= cphy_cause_link_change; | ||
319 | if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO)) | ||
320 | cphy_cause |= cphy_cause_fifo_error; | ||
321 | return cphy_cause; | ||
322 | } | ||
323 | |||
324 | static void vsc8244_destroy(struct cphy *cphy) | ||
325 | { | ||
326 | kfree(cphy); | ||
327 | } | ||
328 | |||
329 | static struct cphy_ops vsc8244_ops = { | ||
330 | .destroy = vsc8244_destroy, | ||
331 | .reset = vsc8244_reset, | ||
332 | .interrupt_enable = vsc8244_intr_enable, | ||
333 | .interrupt_disable = vsc8244_intr_disable, | ||
334 | .interrupt_clear = vsc8244_intr_clear, | ||
335 | .interrupt_handler = vsc8244_intr_handler, | ||
336 | .autoneg_enable = vsc8244_autoneg_enable, | ||
337 | .autoneg_restart = vsc8244_autoneg_restart, | ||
338 | .advertise = vsc8244_advertise, | ||
339 | .set_speed_duplex = vsc8244_set_speed_duplex, | ||
340 | .get_link_status = vsc8244_get_link_status | ||
341 | }; | ||
342 | |||
343 | static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, | ||
344 | struct mdio_ops *mdio_ops) | ||
345 | { | ||
346 | struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL); | ||
347 | |||
348 | if (!cphy) | ||
349 | return NULL; | ||
350 | |||
351 | cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops); | ||
352 | |||
353 | return cphy; | ||
354 | } | ||
355 | |||
356 | |||
357 | static int vsc8244_phy_reset(adapter_t* adapter) | ||
358 | { | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | struct gphy t1_vsc8244_ops = { | ||
363 | vsc8244_phy_create, | ||
364 | vsc8244_phy_reset | ||
365 | }; | ||
366 | |||
367 | |||
diff --git a/drivers/net/chelsio/vsc8244_reg.h b/drivers/net/chelsio/vsc8244_reg.h deleted file mode 100644 index d3c1829055cb..000000000000 --- a/drivers/net/chelsio/vsc8244_reg.h +++ /dev/null | |||
@@ -1,172 +0,0 @@ | |||
1 | /* $Date: 2005/11/23 16:28:53 $ $RCSfile: vsc8244_reg.h,v $ $Revision: 1.1 $ */ | ||
2 | #ifndef CHELSIO_MV8E1XXX_H | ||
3 | #define CHELSIO_MV8E1XXX_H | ||
4 | |||
5 | #ifndef BMCR_SPEED1000 | ||
6 | # define BMCR_SPEED1000 0x40 | ||
7 | #endif | ||
8 | |||
9 | #ifndef ADVERTISE_PAUSE | ||
10 | # define ADVERTISE_PAUSE 0x400 | ||
11 | #endif | ||
12 | #ifndef ADVERTISE_PAUSE_ASYM | ||
13 | # define ADVERTISE_PAUSE_ASYM 0x800 | ||
14 | #endif | ||
15 | |||
16 | /* Gigabit MII registers */ | ||
17 | #define MII_GBMR 1 /* 1000Base-T mode register */ | ||
18 | #define MII_GBCR 9 /* 1000Base-T control register */ | ||
19 | #define MII_GBSR 10 /* 1000Base-T status register */ | ||
20 | |||
21 | /* 1000Base-T control register fields */ | ||
22 | #define GBCR_ADV_1000HALF 0x100 | ||
23 | #define GBCR_ADV_1000FULL 0x200 | ||
24 | #define GBCR_PREFER_MASTER 0x400 | ||
25 | #define GBCR_MANUAL_AS_MASTER 0x800 | ||
26 | #define GBCR_MANUAL_CONFIG_ENABLE 0x1000 | ||
27 | |||
28 | /* 1000Base-T status register fields */ | ||
29 | #define GBSR_LP_1000HALF 0x400 | ||
30 | #define GBSR_LP_1000FULL 0x800 | ||
31 | #define GBSR_REMOTE_OK 0x1000 | ||
32 | #define GBSR_LOCAL_OK 0x2000 | ||
33 | #define GBSR_LOCAL_MASTER 0x4000 | ||
34 | #define GBSR_MASTER_FAULT 0x8000 | ||
35 | |||
36 | /* Vitesse PHY interrupt status bits. */ | ||
37 | #if 0 | ||
38 | #define VSC8244_INTR_JABBER 0x0001 | ||
39 | #define VSC8244_INTR_POLARITY_CHNG 0x0002 | ||
40 | #define VSC8244_INTR_ENG_DETECT_CHNG 0x0010 | ||
41 | #define VSC8244_INTR_DOWNSHIFT 0x0020 | ||
42 | #define VSC8244_INTR_MDI_XOVER_CHNG 0x0040 | ||
43 | #define VSC8244_INTR_FIFO_OVER_UNDER 0x0080 | ||
44 | #define VSC8244_INTR_FALSE_CARRIER 0x0100 | ||
45 | #define VSC8244_INTR_SYMBOL_ERROR 0x0200 | ||
46 | #define VSC8244_INTR_LINK_CHNG 0x0400 | ||
47 | #define VSC8244_INTR_AUTONEG_DONE 0x0800 | ||
48 | #define VSC8244_INTR_PAGE_RECV 0x1000 | ||
49 | #define VSC8244_INTR_DUPLEX_CHNG 0x2000 | ||
50 | #define VSC8244_INTR_SPEED_CHNG 0x4000 | ||
51 | #define VSC8244_INTR_AUTONEG_ERR 0x8000 | ||
52 | #else | ||
53 | //#define VSC8244_INTR_JABBER 0x0001 | ||
54 | //#define VSC8244_INTR_POLARITY_CHNG 0x0002 | ||
55 | //#define VSC8244_INTR_BIT2 0x0004 | ||
56 | //#define VSC8244_INTR_BIT3 0x0008 | ||
57 | #define VSC8244_INTR_RX_ERR 0x0001 | ||
58 | #define VSC8244_INTR_MASTER_SLAVE 0x0002 | ||
59 | #define VSC8244_INTR_CABLE_IMPAIRED 0x0004 | ||
60 | #define VSC8244_INTR_FALSE_CARRIER 0x0008 | ||
61 | //#define VSC8244_INTR_ENG_DETECT_CHNG 0x0010 | ||
62 | //#define VSC8244_INTR_DOWNSHIFT 0x0020 | ||
63 | //#define VSC8244_INTR_MDI_XOVER_CHNG 0x0040 | ||
64 | //#define VSC8244_INTR_FIFO_OVER_UNDER 0x0080 | ||
65 | #define VSC8244_INTR_BIT4 0x0010 | ||
66 | #define VSC8244_INTR_FIFO_RX 0x0020 | ||
67 | #define VSC8244_INTR_FIFO_OVER_UNDER 0x0040 | ||
68 | #define VSC8244_INTR_LOCK_LOST 0x0080 | ||
69 | //#define VSC8244_INTR_FALSE_CARRIER 0x0100 | ||
70 | //#define VSC8244_INTR_SYMBOL_ERROR 0x0200 | ||
71 | //#define VSC8244_INTR_LINK_CHNG 0x0400 | ||
72 | //#define VSC8244_INTR_AUTONEG_DONE 0x0800 | ||
73 | #define VSC8244_INTR_SYMBOL_ERROR 0x0100 | ||
74 | #define VSC8244_INTR_ENG_DETECT_CHNG 0x0200 | ||
75 | #define VSC8244_INTR_AUTONEG_DONE 0x0400 | ||
76 | #define VSC8244_INTR_AUTONEG_ERR 0x0800 | ||
77 | //#define VSC8244_INTR_PAGE_RECV 0x1000 | ||
78 | //#define VSC8244_INTR_DUPLEX_CHNG 0x2000 | ||
79 | //#define VSC8244_INTR_SPEED_CHNG 0x4000 | ||
80 | //#define VSC8244_INTR_AUTONEG_ERR 0x8000 | ||
81 | #define VSC8244_INTR_DUPLEX_CHNG 0x1000 | ||
82 | #define VSC8244_INTR_LINK_CHNG 0x2000 | ||
83 | #define VSC8244_INTR_SPEED_CHNG 0x4000 | ||
84 | #define VSC8244_INTR_STATUS 0x8000 | ||
85 | #endif | ||
86 | |||
87 | |||
88 | /* Vitesse PHY specific registers. */ | ||
89 | #define VSC8244_SPECIFIC_CNTRL_REGISTER 16 | ||
90 | #define VSC8244_SPECIFIC_STATUS_REGISTER 0x1c | ||
91 | #define VSC8244_INTERRUPT_ENABLE_REGISTER 0x19 | ||
92 | #define VSC8244_INTERRUPT_STATUS_REGISTER 0x1a | ||
93 | #define VSC8244_EXT_PHY_SPECIFIC_CNTRL_REGISTER 20 | ||
94 | #define VSC8244_RECV_ERR_CNTR_REGISTER 21 | ||
95 | #define VSC8244_RES_REGISTER 22 | ||
96 | #define VSC8244_GLOBAL_STATUS_REGISTER 23 | ||
97 | #define VSC8244_LED_CONTROL_REGISTER 24 | ||
98 | #define VSC8244_MANUAL_LED_OVERRIDE_REGISTER 25 | ||
99 | #define VSC8244_EXT_PHY_SPECIFIC_CNTRL_2_REGISTER 26 | ||
100 | #define VSC8244_EXT_PHY_SPECIFIC_STATUS_REGISTER 27 | ||
101 | #define VSC8244_VIRTUAL_CABLE_TESTER_REGISTER 28 | ||
102 | #define VSC8244_EXTENDED_ADDR_REGISTER 29 | ||
103 | #define VSC8244_EXTENDED_REGISTER 30 | ||
104 | |||
105 | /* PHY specific control register fields */ | ||
106 | #define S_PSCR_MDI_XOVER_MODE 5 | ||
107 | #define M_PSCR_MDI_XOVER_MODE 0x3 | ||
108 | #define V_PSCR_MDI_XOVER_MODE(x) ((x) << S_PSCR_MDI_XOVER_MODE) | ||
109 | #define G_PSCR_MDI_XOVER_MODE(x) (((x) >> S_PSCR_MDI_XOVER_MODE) & M_PSCR_MDI_XOVER_MODE) | ||
110 | |||
111 | /* Extended PHY specific control register fields */ | ||
112 | #define S_DOWNSHIFT_ENABLE 8 | ||
113 | #define V_DOWNSHIFT_ENABLE (1 << S_DOWNSHIFT_ENABLE) | ||
114 | |||
115 | #define S_DOWNSHIFT_CNT 9 | ||
116 | #define M_DOWNSHIFT_CNT 0x7 | ||
117 | #define V_DOWNSHIFT_CNT(x) ((x) << S_DOWNSHIFT_CNT) | ||
118 | #define G_DOWNSHIFT_CNT(x) (((x) >> S_DOWNSHIFT_CNT) & M_DOWNSHIFT_CNT) | ||
119 | |||
120 | /* PHY specific status register fields */ | ||
121 | #define S_PSSR_JABBER 0 | ||
122 | #define V_PSSR_JABBER (1 << S_PSSR_JABBER) | ||
123 | |||
124 | #define S_PSSR_POLARITY 1 | ||
125 | #define V_PSSR_POLARITY (1 << S_PSSR_POLARITY) | ||
126 | |||
127 | #define S_PSSR_RX_PAUSE 2 | ||
128 | #define V_PSSR_RX_PAUSE (1 << S_PSSR_RX_PAUSE) | ||
129 | |||
130 | #define S_PSSR_TX_PAUSE 3 | ||
131 | #define V_PSSR_TX_PAUSE (1 << S_PSSR_TX_PAUSE) | ||
132 | |||
133 | #define S_PSSR_ENERGY_DETECT 4 | ||
134 | #define V_PSSR_ENERGY_DETECT (1 << S_PSSR_ENERGY_DETECT) | ||
135 | |||
136 | #define S_PSSR_DOWNSHIFT_STATUS 5 | ||
137 | #define V_PSSR_DOWNSHIFT_STATUS (1 << S_PSSR_DOWNSHIFT_STATUS) | ||
138 | |||
139 | #define S_PSSR_MDI 6 | ||
140 | #define V_PSSR_MDI (1 << S_PSSR_MDI) | ||
141 | |||
142 | #define S_PSSR_CABLE_LEN 7 | ||
143 | #define M_PSSR_CABLE_LEN 0x7 | ||
144 | #define V_PSSR_CABLE_LEN(x) ((x) << S_PSSR_CABLE_LEN) | ||
145 | #define G_PSSR_CABLE_LEN(x) (((x) >> S_PSSR_CABLE_LEN) & M_PSSR_CABLE_LEN) | ||
146 | |||
147 | //#define S_PSSR_LINK 10 | ||
148 | //#define S_PSSR_LINK 13 | ||
149 | #define S_PSSR_LINK 2 | ||
150 | #define V_PSSR_LINK (1 << S_PSSR_LINK) | ||
151 | |||
152 | //#define S_PSSR_STATUS_RESOLVED 11 | ||
153 | //#define S_PSSR_STATUS_RESOLVED 10 | ||
154 | #define S_PSSR_STATUS_RESOLVED 15 | ||
155 | #define V_PSSR_STATUS_RESOLVED (1 << S_PSSR_STATUS_RESOLVED) | ||
156 | |||
157 | #define S_PSSR_PAGE_RECEIVED 12 | ||
158 | #define V_PSSR_PAGE_RECEIVED (1 << S_PSSR_PAGE_RECEIVED) | ||
159 | |||
160 | //#define S_PSSR_DUPLEX 13 | ||
161 | //#define S_PSSR_DUPLEX 12 | ||
162 | #define S_PSSR_DUPLEX 5 | ||
163 | #define V_PSSR_DUPLEX (1 << S_PSSR_DUPLEX) | ||
164 | |||
165 | //#define S_PSSR_SPEED 14 | ||
166 | //#define S_PSSR_SPEED 14 | ||
167 | #define S_PSSR_SPEED 3 | ||
168 | #define M_PSSR_SPEED 0x3 | ||
169 | #define V_PSSR_SPEED(x) ((x) << S_PSSR_SPEED) | ||
170 | #define G_PSSR_SPEED(x) (((x) >> S_PSSR_SPEED) & M_PSSR_SPEED) | ||
171 | |||
172 | #endif | ||
diff --git a/drivers/net/e100.c b/drivers/net/e100.c index 4d0e0aea72bf..61696637a21e 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c | |||
@@ -159,7 +159,7 @@ | |||
159 | 159 | ||
160 | #define DRV_NAME "e100" | 160 | #define DRV_NAME "e100" |
161 | #define DRV_EXT "-NAPI" | 161 | #define DRV_EXT "-NAPI" |
162 | #define DRV_VERSION "3.5.17-k2"DRV_EXT | 162 | #define DRV_VERSION "3.5.17-k4"DRV_EXT |
163 | #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" | 163 | #define DRV_DESCRIPTION "Intel(R) PRO/100 Network Driver" |
164 | #define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" | 164 | #define DRV_COPYRIGHT "Copyright(c) 1999-2006 Intel Corporation" |
165 | #define PFX DRV_NAME ": " | 165 | #define PFX DRV_NAME ": " |
@@ -174,10 +174,13 @@ MODULE_VERSION(DRV_VERSION); | |||
174 | 174 | ||
175 | static int debug = 3; | 175 | static int debug = 3; |
176 | static int eeprom_bad_csum_allow = 0; | 176 | static int eeprom_bad_csum_allow = 0; |
177 | static int use_io = 0; | ||
177 | module_param(debug, int, 0); | 178 | module_param(debug, int, 0); |
178 | module_param(eeprom_bad_csum_allow, int, 0); | 179 | module_param(eeprom_bad_csum_allow, int, 0); |
180 | module_param(use_io, int, 0); | ||
179 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); | 181 | MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); |
180 | MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums"); | 182 | MODULE_PARM_DESC(eeprom_bad_csum_allow, "Allow bad eeprom checksums"); |
183 | MODULE_PARM_DESC(use_io, "Force use of i/o access mode"); | ||
181 | #define DPRINTK(nlevel, klevel, fmt, args...) \ | 184 | #define DPRINTK(nlevel, klevel, fmt, args...) \ |
182 | (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \ | 185 | (void)((NETIF_MSG_##nlevel & nic->msg_enable) && \ |
183 | printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \ | 186 | printk(KERN_##klevel PFX "%s: %s: " fmt, nic->netdev->name, \ |
@@ -282,12 +285,6 @@ enum scb_status { | |||
282 | rus_mask = 0x3C, | 285 | rus_mask = 0x3C, |
283 | }; | 286 | }; |
284 | 287 | ||
285 | enum ru_state { | ||
286 | RU_SUSPENDED = 0, | ||
287 | RU_RUNNING = 1, | ||
288 | RU_UNINITIALIZED = -1, | ||
289 | }; | ||
290 | |||
291 | enum scb_stat_ack { | 288 | enum scb_stat_ack { |
292 | stat_ack_not_ours = 0x00, | 289 | stat_ack_not_ours = 0x00, |
293 | stat_ack_sw_gen = 0x04, | 290 | stat_ack_sw_gen = 0x04, |
@@ -529,7 +526,6 @@ struct nic { | |||
529 | struct rx *rx_to_use; | 526 | struct rx *rx_to_use; |
530 | struct rx *rx_to_clean; | 527 | struct rx *rx_to_clean; |
531 | struct rfd blank_rfd; | 528 | struct rfd blank_rfd; |
532 | enum ru_state ru_running; | ||
533 | 529 | ||
534 | spinlock_t cb_lock ____cacheline_aligned; | 530 | spinlock_t cb_lock ____cacheline_aligned; |
535 | spinlock_t cmd_lock; | 531 | spinlock_t cmd_lock; |
@@ -591,7 +587,7 @@ static inline void e100_write_flush(struct nic *nic) | |||
591 | { | 587 | { |
592 | /* Flush previous PCI writes through intermediate bridges | 588 | /* Flush previous PCI writes through intermediate bridges |
593 | * by doing a benign read */ | 589 | * by doing a benign read */ |
594 | (void)readb(&nic->csr->scb.status); | 590 | (void)ioread8(&nic->csr->scb.status); |
595 | } | 591 | } |
596 | 592 | ||
597 | static void e100_enable_irq(struct nic *nic) | 593 | static void e100_enable_irq(struct nic *nic) |
@@ -599,7 +595,7 @@ static void e100_enable_irq(struct nic *nic) | |||
599 | unsigned long flags; | 595 | unsigned long flags; |
600 | 596 | ||
601 | spin_lock_irqsave(&nic->cmd_lock, flags); | 597 | spin_lock_irqsave(&nic->cmd_lock, flags); |
602 | writeb(irq_mask_none, &nic->csr->scb.cmd_hi); | 598 | iowrite8(irq_mask_none, &nic->csr->scb.cmd_hi); |
603 | e100_write_flush(nic); | 599 | e100_write_flush(nic); |
604 | spin_unlock_irqrestore(&nic->cmd_lock, flags); | 600 | spin_unlock_irqrestore(&nic->cmd_lock, flags); |
605 | } | 601 | } |
@@ -609,7 +605,7 @@ static void e100_disable_irq(struct nic *nic) | |||
609 | unsigned long flags; | 605 | unsigned long flags; |
610 | 606 | ||
611 | spin_lock_irqsave(&nic->cmd_lock, flags); | 607 | spin_lock_irqsave(&nic->cmd_lock, flags); |
612 | writeb(irq_mask_all, &nic->csr->scb.cmd_hi); | 608 | iowrite8(irq_mask_all, &nic->csr->scb.cmd_hi); |
613 | e100_write_flush(nic); | 609 | e100_write_flush(nic); |
614 | spin_unlock_irqrestore(&nic->cmd_lock, flags); | 610 | spin_unlock_irqrestore(&nic->cmd_lock, flags); |
615 | } | 611 | } |
@@ -618,11 +614,11 @@ static void e100_hw_reset(struct nic *nic) | |||
618 | { | 614 | { |
619 | /* Put CU and RU into idle with a selective reset to get | 615 | /* Put CU and RU into idle with a selective reset to get |
620 | * device off of PCI bus */ | 616 | * device off of PCI bus */ |
621 | writel(selective_reset, &nic->csr->port); | 617 | iowrite32(selective_reset, &nic->csr->port); |
622 | e100_write_flush(nic); udelay(20); | 618 | e100_write_flush(nic); udelay(20); |
623 | 619 | ||
624 | /* Now fully reset device */ | 620 | /* Now fully reset device */ |
625 | writel(software_reset, &nic->csr->port); | 621 | iowrite32(software_reset, &nic->csr->port); |
626 | e100_write_flush(nic); udelay(20); | 622 | e100_write_flush(nic); udelay(20); |
627 | 623 | ||
628 | /* Mask off our interrupt line - it's unmasked after reset */ | 624 | /* Mask off our interrupt line - it's unmasked after reset */ |
@@ -639,7 +635,7 @@ static int e100_self_test(struct nic *nic) | |||
639 | nic->mem->selftest.signature = 0; | 635 | nic->mem->selftest.signature = 0; |
640 | nic->mem->selftest.result = 0xFFFFFFFF; | 636 | nic->mem->selftest.result = 0xFFFFFFFF; |
641 | 637 | ||
642 | writel(selftest | dma_addr, &nic->csr->port); | 638 | iowrite32(selftest | dma_addr, &nic->csr->port); |
643 | e100_write_flush(nic); | 639 | e100_write_flush(nic); |
644 | /* Wait 10 msec for self-test to complete */ | 640 | /* Wait 10 msec for self-test to complete */ |
645 | msleep(10); | 641 | msleep(10); |
@@ -677,23 +673,23 @@ static void e100_eeprom_write(struct nic *nic, u16 addr_len, u16 addr, u16 data) | |||
677 | for(j = 0; j < 3; j++) { | 673 | for(j = 0; j < 3; j++) { |
678 | 674 | ||
679 | /* Chip select */ | 675 | /* Chip select */ |
680 | writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); | 676 | iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo); |
681 | e100_write_flush(nic); udelay(4); | 677 | e100_write_flush(nic); udelay(4); |
682 | 678 | ||
683 | for(i = 31; i >= 0; i--) { | 679 | for(i = 31; i >= 0; i--) { |
684 | ctrl = (cmd_addr_data[j] & (1 << i)) ? | 680 | ctrl = (cmd_addr_data[j] & (1 << i)) ? |
685 | eecs | eedi : eecs; | 681 | eecs | eedi : eecs; |
686 | writeb(ctrl, &nic->csr->eeprom_ctrl_lo); | 682 | iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo); |
687 | e100_write_flush(nic); udelay(4); | 683 | e100_write_flush(nic); udelay(4); |
688 | 684 | ||
689 | writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); | 685 | iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); |
690 | e100_write_flush(nic); udelay(4); | 686 | e100_write_flush(nic); udelay(4); |
691 | } | 687 | } |
692 | /* Wait 10 msec for cmd to complete */ | 688 | /* Wait 10 msec for cmd to complete */ |
693 | msleep(10); | 689 | msleep(10); |
694 | 690 | ||
695 | /* Chip deselect */ | 691 | /* Chip deselect */ |
696 | writeb(0, &nic->csr->eeprom_ctrl_lo); | 692 | iowrite8(0, &nic->csr->eeprom_ctrl_lo); |
697 | e100_write_flush(nic); udelay(4); | 693 | e100_write_flush(nic); udelay(4); |
698 | } | 694 | } |
699 | }; | 695 | }; |
@@ -709,21 +705,21 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) | |||
709 | cmd_addr_data = ((op_read << *addr_len) | addr) << 16; | 705 | cmd_addr_data = ((op_read << *addr_len) | addr) << 16; |
710 | 706 | ||
711 | /* Chip select */ | 707 | /* Chip select */ |
712 | writeb(eecs | eesk, &nic->csr->eeprom_ctrl_lo); | 708 | iowrite8(eecs | eesk, &nic->csr->eeprom_ctrl_lo); |
713 | e100_write_flush(nic); udelay(4); | 709 | e100_write_flush(nic); udelay(4); |
714 | 710 | ||
715 | /* Bit-bang to read word from eeprom */ | 711 | /* Bit-bang to read word from eeprom */ |
716 | for(i = 31; i >= 0; i--) { | 712 | for(i = 31; i >= 0; i--) { |
717 | ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs; | 713 | ctrl = (cmd_addr_data & (1 << i)) ? eecs | eedi : eecs; |
718 | writeb(ctrl, &nic->csr->eeprom_ctrl_lo); | 714 | iowrite8(ctrl, &nic->csr->eeprom_ctrl_lo); |
719 | e100_write_flush(nic); udelay(4); | 715 | e100_write_flush(nic); udelay(4); |
720 | 716 | ||
721 | writeb(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); | 717 | iowrite8(ctrl | eesk, &nic->csr->eeprom_ctrl_lo); |
722 | e100_write_flush(nic); udelay(4); | 718 | e100_write_flush(nic); udelay(4); |
723 | 719 | ||
724 | /* Eeprom drives a dummy zero to EEDO after receiving | 720 | /* Eeprom drives a dummy zero to EEDO after receiving |
725 | * complete address. Use this to adjust addr_len. */ | 721 | * complete address. Use this to adjust addr_len. */ |
726 | ctrl = readb(&nic->csr->eeprom_ctrl_lo); | 722 | ctrl = ioread8(&nic->csr->eeprom_ctrl_lo); |
727 | if(!(ctrl & eedo) && i > 16) { | 723 | if(!(ctrl & eedo) && i > 16) { |
728 | *addr_len -= (i - 16); | 724 | *addr_len -= (i - 16); |
729 | i = 17; | 725 | i = 17; |
@@ -733,7 +729,7 @@ static u16 e100_eeprom_read(struct nic *nic, u16 *addr_len, u16 addr) | |||
733 | } | 729 | } |
734 | 730 | ||
735 | /* Chip deselect */ | 731 | /* Chip deselect */ |
736 | writeb(0, &nic->csr->eeprom_ctrl_lo); | 732 | iowrite8(0, &nic->csr->eeprom_ctrl_lo); |
737 | e100_write_flush(nic); udelay(4); | 733 | e100_write_flush(nic); udelay(4); |
738 | 734 | ||
739 | return le16_to_cpu(data); | 735 | return le16_to_cpu(data); |
@@ -804,7 +800,7 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) | |||
804 | 800 | ||
805 | /* Previous command is accepted when SCB clears */ | 801 | /* Previous command is accepted when SCB clears */ |
806 | for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) { | 802 | for(i = 0; i < E100_WAIT_SCB_TIMEOUT; i++) { |
807 | if(likely(!readb(&nic->csr->scb.cmd_lo))) | 803 | if(likely(!ioread8(&nic->csr->scb.cmd_lo))) |
808 | break; | 804 | break; |
809 | cpu_relax(); | 805 | cpu_relax(); |
810 | if(unlikely(i > E100_WAIT_SCB_FAST)) | 806 | if(unlikely(i > E100_WAIT_SCB_FAST)) |
@@ -816,8 +812,8 @@ static int e100_exec_cmd(struct nic *nic, u8 cmd, dma_addr_t dma_addr) | |||
816 | } | 812 | } |
817 | 813 | ||
818 | if(unlikely(cmd != cuc_resume)) | 814 | if(unlikely(cmd != cuc_resume)) |
819 | writel(dma_addr, &nic->csr->scb.gen_ptr); | 815 | iowrite32(dma_addr, &nic->csr->scb.gen_ptr); |
820 | writeb(cmd, &nic->csr->scb.cmd_lo); | 816 | iowrite8(cmd, &nic->csr->scb.cmd_lo); |
821 | 817 | ||
822 | err_unlock: | 818 | err_unlock: |
823 | spin_unlock_irqrestore(&nic->cmd_lock, flags); | 819 | spin_unlock_irqrestore(&nic->cmd_lock, flags); |
@@ -895,7 +891,7 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) | |||
895 | */ | 891 | */ |
896 | spin_lock_irqsave(&nic->mdio_lock, flags); | 892 | spin_lock_irqsave(&nic->mdio_lock, flags); |
897 | for (i = 100; i; --i) { | 893 | for (i = 100; i; --i) { |
898 | if (readl(&nic->csr->mdi_ctrl) & mdi_ready) | 894 | if (ioread32(&nic->csr->mdi_ctrl) & mdi_ready) |
899 | break; | 895 | break; |
900 | udelay(20); | 896 | udelay(20); |
901 | } | 897 | } |
@@ -905,11 +901,11 @@ static u16 mdio_ctrl(struct nic *nic, u32 addr, u32 dir, u32 reg, u16 data) | |||
905 | spin_unlock_irqrestore(&nic->mdio_lock, flags); | 901 | spin_unlock_irqrestore(&nic->mdio_lock, flags); |
906 | return 0; /* No way to indicate timeout error */ | 902 | return 0; /* No way to indicate timeout error */ |
907 | } | 903 | } |
908 | writel((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); | 904 | iowrite32((reg << 16) | (addr << 21) | dir | data, &nic->csr->mdi_ctrl); |
909 | 905 | ||
910 | for (i = 0; i < 100; i++) { | 906 | for (i = 0; i < 100; i++) { |
911 | udelay(20); | 907 | udelay(20); |
912 | if ((data_out = readl(&nic->csr->mdi_ctrl)) & mdi_ready) | 908 | if ((data_out = ioread32(&nic->csr->mdi_ctrl)) & mdi_ready) |
913 | break; | 909 | break; |
914 | } | 910 | } |
915 | spin_unlock_irqrestore(&nic->mdio_lock, flags); | 911 | spin_unlock_irqrestore(&nic->mdio_lock, flags); |
@@ -951,7 +947,7 @@ static void e100_get_defaults(struct nic *nic) | |||
951 | ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i)); | 947 | ((nic->mac >= mac_82558_D101_A4) ? cb_cid : cb_i)); |
952 | 948 | ||
953 | /* Template for a freshly allocated RFD */ | 949 | /* Template for a freshly allocated RFD */ |
954 | nic->blank_rfd.command = cpu_to_le16(cb_el); | 950 | nic->blank_rfd.command = cpu_to_le16(cb_el & cb_s); |
955 | nic->blank_rfd.rbd = 0xFFFFFFFF; | 951 | nic->blank_rfd.rbd = 0xFFFFFFFF; |
956 | nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); | 952 | nic->blank_rfd.size = cpu_to_le16(VLAN_ETH_FRAME_LEN); |
957 | 953 | ||
@@ -1318,7 +1314,7 @@ static inline int e100_exec_cb_wait(struct nic *nic, struct sk_buff *skb, | |||
1318 | } | 1314 | } |
1319 | 1315 | ||
1320 | /* ack any interupts, something could have been set */ | 1316 | /* ack any interupts, something could have been set */ |
1321 | writeb(~0, &nic->csr->scb.stat_ack); | 1317 | iowrite8(~0, &nic->csr->scb.stat_ack); |
1322 | 1318 | ||
1323 | /* if the command failed, or is not OK, notify and return */ | 1319 | /* if the command failed, or is not OK, notify and return */ |
1324 | if (!counter || !(cb->status & cpu_to_le16(cb_ok))) { | 1320 | if (!counter || !(cb->status & cpu_to_le16(cb_ok))) { |
@@ -1580,7 +1576,7 @@ static void e100_watchdog(unsigned long data) | |||
1580 | * accidentally, due to hardware that shares a register between the | 1576 | * accidentally, due to hardware that shares a register between the |
1581 | * interrupt mask bit and the SW Interrupt generation bit */ | 1577 | * interrupt mask bit and the SW Interrupt generation bit */ |
1582 | spin_lock_irq(&nic->cmd_lock); | 1578 | spin_lock_irq(&nic->cmd_lock); |
1583 | writeb(readb(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi); | 1579 | iowrite8(ioread8(&nic->csr->scb.cmd_hi) | irq_sw_gen,&nic->csr->scb.cmd_hi); |
1584 | e100_write_flush(nic); | 1580 | e100_write_flush(nic); |
1585 | spin_unlock_irq(&nic->cmd_lock); | 1581 | spin_unlock_irq(&nic->cmd_lock); |
1586 | 1582 | ||
@@ -1746,19 +1742,11 @@ static int e100_alloc_cbs(struct nic *nic) | |||
1746 | return 0; | 1742 | return 0; |
1747 | } | 1743 | } |
1748 | 1744 | ||
1749 | static inline void e100_start_receiver(struct nic *nic, struct rx *rx) | 1745 | static inline void e100_start_receiver(struct nic *nic) |
1750 | { | 1746 | { |
1751 | if(!nic->rxs) return; | 1747 | /* Start if RFA is non-NULL */ |
1752 | if(RU_SUSPENDED != nic->ru_running) return; | 1748 | if(nic->rx_to_clean->skb) |
1753 | 1749 | e100_exec_cmd(nic, ruc_start, nic->rx_to_clean->dma_addr); | |
1754 | /* handle init time starts */ | ||
1755 | if(!rx) rx = nic->rxs; | ||
1756 | |||
1757 | /* (Re)start RU if suspended or idle and RFA is non-NULL */ | ||
1758 | if(rx->skb) { | ||
1759 | e100_exec_cmd(nic, ruc_start, rx->dma_addr); | ||
1760 | nic->ru_running = RU_RUNNING; | ||
1761 | } | ||
1762 | } | 1750 | } |
1763 | 1751 | ||
1764 | #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) | 1752 | #define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN) |
@@ -1787,7 +1775,7 @@ static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx) | |||
1787 | put_unaligned(cpu_to_le32(rx->dma_addr), | 1775 | put_unaligned(cpu_to_le32(rx->dma_addr), |
1788 | (u32 *)&prev_rfd->link); | 1776 | (u32 *)&prev_rfd->link); |
1789 | wmb(); | 1777 | wmb(); |
1790 | prev_rfd->command &= ~cpu_to_le16(cb_el); | 1778 | prev_rfd->command &= ~cpu_to_le16(cb_el & cb_s); |
1791 | pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, | 1779 | pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr, |
1792 | sizeof(struct rfd), PCI_DMA_TODEVICE); | 1780 | sizeof(struct rfd), PCI_DMA_TODEVICE); |
1793 | } | 1781 | } |
@@ -1825,10 +1813,6 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, | |||
1825 | pci_unmap_single(nic->pdev, rx->dma_addr, | 1813 | pci_unmap_single(nic->pdev, rx->dma_addr, |
1826 | RFD_BUF_LEN, PCI_DMA_FROMDEVICE); | 1814 | RFD_BUF_LEN, PCI_DMA_FROMDEVICE); |
1827 | 1815 | ||
1828 | /* this allows for a fast restart without re-enabling interrupts */ | ||
1829 | if(le16_to_cpu(rfd->command) & cb_el) | ||
1830 | nic->ru_running = RU_SUSPENDED; | ||
1831 | |||
1832 | /* Pull off the RFD and put the actual data (minus eth hdr) */ | 1816 | /* Pull off the RFD and put the actual data (minus eth hdr) */ |
1833 | skb_reserve(skb, sizeof(struct rfd)); | 1817 | skb_reserve(skb, sizeof(struct rfd)); |
1834 | skb_put(skb, actual_size); | 1818 | skb_put(skb, actual_size); |
@@ -1859,45 +1843,18 @@ static void e100_rx_clean(struct nic *nic, unsigned int *work_done, | |||
1859 | unsigned int work_to_do) | 1843 | unsigned int work_to_do) |
1860 | { | 1844 | { |
1861 | struct rx *rx; | 1845 | struct rx *rx; |
1862 | int restart_required = 0; | ||
1863 | struct rx *rx_to_start = NULL; | ||
1864 | |||
1865 | /* are we already rnr? then pay attention!!! this ensures that | ||
1866 | * the state machine progression never allows a start with a | ||
1867 | * partially cleaned list, avoiding a race between hardware | ||
1868 | * and rx_to_clean when in NAPI mode */ | ||
1869 | if(RU_SUSPENDED == nic->ru_running) | ||
1870 | restart_required = 1; | ||
1871 | 1846 | ||
1872 | /* Indicate newly arrived packets */ | 1847 | /* Indicate newly arrived packets */ |
1873 | for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { | 1848 | for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) { |
1874 | int err = e100_rx_indicate(nic, rx, work_done, work_to_do); | 1849 | if(e100_rx_indicate(nic, rx, work_done, work_to_do)) |
1875 | if(-EAGAIN == err) { | ||
1876 | /* hit quota so have more work to do, restart once | ||
1877 | * cleanup is complete */ | ||
1878 | restart_required = 0; | ||
1879 | break; | ||
1880 | } else if(-ENODATA == err) | ||
1881 | break; /* No more to clean */ | 1850 | break; /* No more to clean */ |
1882 | } | 1851 | } |
1883 | 1852 | ||
1884 | /* save our starting point as the place we'll restart the receiver */ | ||
1885 | if(restart_required) | ||
1886 | rx_to_start = nic->rx_to_clean; | ||
1887 | |||
1888 | /* Alloc new skbs to refill list */ | 1853 | /* Alloc new skbs to refill list */ |
1889 | for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { | 1854 | for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) { |
1890 | if(unlikely(e100_rx_alloc_skb(nic, rx))) | 1855 | if(unlikely(e100_rx_alloc_skb(nic, rx))) |
1891 | break; /* Better luck next time (see watchdog) */ | 1856 | break; /* Better luck next time (see watchdog) */ |
1892 | } | 1857 | } |
1893 | |||
1894 | if(restart_required) { | ||
1895 | // ack the rnr? | ||
1896 | writeb(stat_ack_rnr, &nic->csr->scb.stat_ack); | ||
1897 | e100_start_receiver(nic, rx_to_start); | ||
1898 | if(work_done) | ||
1899 | (*work_done)++; | ||
1900 | } | ||
1901 | } | 1858 | } |
1902 | 1859 | ||
1903 | static void e100_rx_clean_list(struct nic *nic) | 1860 | static void e100_rx_clean_list(struct nic *nic) |
@@ -1905,8 +1862,6 @@ static void e100_rx_clean_list(struct nic *nic) | |||
1905 | struct rx *rx; | 1862 | struct rx *rx; |
1906 | unsigned int i, count = nic->params.rfds.count; | 1863 | unsigned int i, count = nic->params.rfds.count; |
1907 | 1864 | ||
1908 | nic->ru_running = RU_UNINITIALIZED; | ||
1909 | |||
1910 | if(nic->rxs) { | 1865 | if(nic->rxs) { |
1911 | for(rx = nic->rxs, i = 0; i < count; rx++, i++) { | 1866 | for(rx = nic->rxs, i = 0; i < count; rx++, i++) { |
1912 | if(rx->skb) { | 1867 | if(rx->skb) { |
@@ -1928,7 +1883,6 @@ static int e100_rx_alloc_list(struct nic *nic) | |||
1928 | unsigned int i, count = nic->params.rfds.count; | 1883 | unsigned int i, count = nic->params.rfds.count; |
1929 | 1884 | ||
1930 | nic->rx_to_use = nic->rx_to_clean = NULL; | 1885 | nic->rx_to_use = nic->rx_to_clean = NULL; |
1931 | nic->ru_running = RU_UNINITIALIZED; | ||
1932 | 1886 | ||
1933 | if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC))) | 1887 | if(!(nic->rxs = kcalloc(count, sizeof(struct rx), GFP_ATOMIC))) |
1934 | return -ENOMEM; | 1888 | return -ENOMEM; |
@@ -1943,7 +1897,6 @@ static int e100_rx_alloc_list(struct nic *nic) | |||
1943 | } | 1897 | } |
1944 | 1898 | ||
1945 | nic->rx_to_use = nic->rx_to_clean = nic->rxs; | 1899 | nic->rx_to_use = nic->rx_to_clean = nic->rxs; |
1946 | nic->ru_running = RU_SUSPENDED; | ||
1947 | 1900 | ||
1948 | return 0; | 1901 | return 0; |
1949 | } | 1902 | } |
@@ -1952,7 +1905,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id) | |||
1952 | { | 1905 | { |
1953 | struct net_device *netdev = dev_id; | 1906 | struct net_device *netdev = dev_id; |
1954 | struct nic *nic = netdev_priv(netdev); | 1907 | struct nic *nic = netdev_priv(netdev); |
1955 | u8 stat_ack = readb(&nic->csr->scb.stat_ack); | 1908 | u8 stat_ack = ioread8(&nic->csr->scb.stat_ack); |
1956 | 1909 | ||
1957 | DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack); | 1910 | DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack); |
1958 | 1911 | ||
@@ -1961,11 +1914,7 @@ static irqreturn_t e100_intr(int irq, void *dev_id) | |||
1961 | return IRQ_NONE; | 1914 | return IRQ_NONE; |
1962 | 1915 | ||
1963 | /* Ack interrupt(s) */ | 1916 | /* Ack interrupt(s) */ |
1964 | writeb(stat_ack, &nic->csr->scb.stat_ack); | 1917 | iowrite8(stat_ack, &nic->csr->scb.stat_ack); |
1965 | |||
1966 | /* We hit Receive No Resource (RNR); restart RU after cleaning */ | ||
1967 | if(stat_ack & stat_ack_rnr) | ||
1968 | nic->ru_running = RU_SUSPENDED; | ||
1969 | 1918 | ||
1970 | if(likely(netif_rx_schedule_prep(netdev))) { | 1919 | if(likely(netif_rx_schedule_prep(netdev))) { |
1971 | e100_disable_irq(nic); | 1920 | e100_disable_irq(nic); |
@@ -2058,7 +2007,7 @@ static int e100_up(struct nic *nic) | |||
2058 | if((err = e100_hw_init(nic))) | 2007 | if((err = e100_hw_init(nic))) |
2059 | goto err_clean_cbs; | 2008 | goto err_clean_cbs; |
2060 | e100_set_multicast_list(nic->netdev); | 2009 | e100_set_multicast_list(nic->netdev); |
2061 | e100_start_receiver(nic, NULL); | 2010 | e100_start_receiver(nic); |
2062 | mod_timer(&nic->watchdog, jiffies); | 2011 | mod_timer(&nic->watchdog, jiffies); |
2063 | if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED, | 2012 | if((err = request_irq(nic->pdev->irq, e100_intr, IRQF_SHARED, |
2064 | nic->netdev->name, nic->netdev))) | 2013 | nic->netdev->name, nic->netdev))) |
@@ -2107,7 +2056,7 @@ static void e100_tx_timeout_task(struct work_struct *work) | |||
2107 | struct net_device *netdev = nic->netdev; | 2056 | struct net_device *netdev = nic->netdev; |
2108 | 2057 | ||
2109 | DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", | 2058 | DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n", |
2110 | readb(&nic->csr->scb.status)); | 2059 | ioread8(&nic->csr->scb.status)); |
2111 | e100_down(netdev_priv(netdev)); | 2060 | e100_down(netdev_priv(netdev)); |
2112 | e100_up(netdev_priv(netdev)); | 2061 | e100_up(netdev_priv(netdev)); |
2113 | } | 2062 | } |
@@ -2139,7 +2088,7 @@ static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode) | |||
2139 | mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, | 2088 | mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR, |
2140 | BMCR_LOOPBACK); | 2089 | BMCR_LOOPBACK); |
2141 | 2090 | ||
2142 | e100_start_receiver(nic, NULL); | 2091 | e100_start_receiver(nic); |
2143 | 2092 | ||
2144 | if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) { | 2093 | if(!(skb = netdev_alloc_skb(nic->netdev, ETH_DATA_LEN))) { |
2145 | err = -ENOMEM; | 2094 | err = -ENOMEM; |
@@ -2230,9 +2179,9 @@ static void e100_get_regs(struct net_device *netdev, | |||
2230 | int i; | 2179 | int i; |
2231 | 2180 | ||
2232 | regs->version = (1 << 24) | nic->rev_id; | 2181 | regs->version = (1 << 24) | nic->rev_id; |
2233 | buff[0] = readb(&nic->csr->scb.cmd_hi) << 24 | | 2182 | buff[0] = ioread8(&nic->csr->scb.cmd_hi) << 24 | |
2234 | readb(&nic->csr->scb.cmd_lo) << 16 | | 2183 | ioread8(&nic->csr->scb.cmd_lo) << 16 | |
2235 | readw(&nic->csr->scb.status); | 2184 | ioread16(&nic->csr->scb.status); |
2236 | for(i = E100_PHY_REGS; i >= 0; i--) | 2185 | for(i = E100_PHY_REGS; i >= 0; i--) |
2237 | buff[1 + E100_PHY_REGS - i] = | 2186 | buff[1 + E100_PHY_REGS - i] = |
2238 | mdio_read(netdev, nic->mii.phy_id, i); | 2187 | mdio_read(netdev, nic->mii.phy_id, i); |
@@ -2604,7 +2553,10 @@ static int __devinit e100_probe(struct pci_dev *pdev, | |||
2604 | SET_MODULE_OWNER(netdev); | 2553 | SET_MODULE_OWNER(netdev); |
2605 | SET_NETDEV_DEV(netdev, &pdev->dev); | 2554 | SET_NETDEV_DEV(netdev, &pdev->dev); |
2606 | 2555 | ||
2607 | nic->csr = ioremap(pci_resource_start(pdev, 0), sizeof(struct csr)); | 2556 | if (use_io) |
2557 | DPRINTK(PROBE, INFO, "using i/o access mode\n"); | ||
2558 | |||
2559 | nic->csr = pci_iomap(pdev, (use_io ? 1 : 0), sizeof(struct csr)); | ||
2608 | if(!nic->csr) { | 2560 | if(!nic->csr) { |
2609 | DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n"); | 2561 | DPRINTK(PROBE, ERR, "Cannot map device registers, aborting.\n"); |
2610 | err = -ENOMEM; | 2562 | err = -ENOMEM; |
@@ -2651,11 +2603,16 @@ static int __devinit e100_probe(struct pci_dev *pdev, | |||
2651 | 2603 | ||
2652 | memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); | 2604 | memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN); |
2653 | memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); | 2605 | memcpy(netdev->perm_addr, nic->eeprom, ETH_ALEN); |
2654 | if(!is_valid_ether_addr(netdev->perm_addr)) { | 2606 | if (!is_valid_ether_addr(netdev->perm_addr)) { |
2655 | DPRINTK(PROBE, ERR, "Invalid MAC address from " | 2607 | if (!eeprom_bad_csum_allow) { |
2656 | "EEPROM, aborting.\n"); | 2608 | DPRINTK(PROBE, ERR, "Invalid MAC address from " |
2657 | err = -EAGAIN; | 2609 | "EEPROM, aborting.\n"); |
2658 | goto err_out_free; | 2610 | err = -EAGAIN; |
2611 | goto err_out_free; | ||
2612 | } else { | ||
2613 | DPRINTK(PROBE, ERR, "Invalid MAC address from EEPROM, " | ||
2614 | "you MUST configure one.\n"); | ||
2615 | } | ||
2659 | } | 2616 | } |
2660 | 2617 | ||
2661 | /* Wol magic packet can be enabled from eeprom */ | 2618 | /* Wol magic packet can be enabled from eeprom */ |
@@ -2676,7 +2633,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, | |||
2676 | 2633 | ||
2677 | DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, " | 2634 | DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, " |
2678 | "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", | 2635 | "MAC addr %02X:%02X:%02X:%02X:%02X:%02X\n", |
2679 | (unsigned long long)pci_resource_start(pdev, 0), pdev->irq, | 2636 | (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), pdev->irq, |
2680 | netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], | 2637 | netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], |
2681 | netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); | 2638 | netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); |
2682 | 2639 | ||
@@ -2685,7 +2642,7 @@ static int __devinit e100_probe(struct pci_dev *pdev, | |||
2685 | err_out_free: | 2642 | err_out_free: |
2686 | e100_free(nic); | 2643 | e100_free(nic); |
2687 | err_out_iounmap: | 2644 | err_out_iounmap: |
2688 | iounmap(nic->csr); | 2645 | pci_iounmap(pdev, nic->csr); |
2689 | err_out_free_res: | 2646 | err_out_free_res: |
2690 | pci_release_regions(pdev); | 2647 | pci_release_regions(pdev); |
2691 | err_out_disable_pdev: | 2648 | err_out_disable_pdev: |
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index dd4b728ac4b5..a9ea67e75c1b 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h | |||
@@ -155,9 +155,6 @@ struct e1000_adapter; | |||
155 | /* Number of packet split data buffers (not including the header buffer) */ | 155 | /* Number of packet split data buffers (not including the header buffer) */ |
156 | #define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1 | 156 | #define PS_PAGE_BUFFERS MAX_PS_BUFFERS-1 |
157 | 157 | ||
158 | /* only works for sizes that are powers of 2 */ | ||
159 | #define E1000_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) | ||
160 | |||
161 | /* wrapper around a pointer to a socket buffer, | 158 | /* wrapper around a pointer to a socket buffer, |
162 | * so a DMA handle can be stored along with the buffer */ | 159 | * so a DMA handle can be stored along with the buffer */ |
163 | struct e1000_buffer { | 160 | struct e1000_buffer { |
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c index 6777887295f5..bb08375b5f13 100644 --- a/drivers/net/e1000/e1000_ethtool.c +++ b/drivers/net/e1000/e1000_ethtool.c | |||
@@ -654,14 +654,11 @@ e1000_set_ringparam(struct net_device *netdev, | |||
654 | e1000_mac_type mac_type = adapter->hw.mac_type; | 654 | e1000_mac_type mac_type = adapter->hw.mac_type; |
655 | struct e1000_tx_ring *txdr, *tx_old; | 655 | struct e1000_tx_ring *txdr, *tx_old; |
656 | struct e1000_rx_ring *rxdr, *rx_old; | 656 | struct e1000_rx_ring *rxdr, *rx_old; |
657 | int i, err, tx_ring_size, rx_ring_size; | 657 | int i, err; |
658 | 658 | ||
659 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) | 659 | if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) |
660 | return -EINVAL; | 660 | return -EINVAL; |
661 | 661 | ||
662 | tx_ring_size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; | ||
663 | rx_ring_size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; | ||
664 | |||
665 | while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) | 662 | while (test_and_set_bit(__E1000_RESETTING, &adapter->flags)) |
666 | msleep(1); | 663 | msleep(1); |
667 | 664 | ||
@@ -672,11 +669,11 @@ e1000_set_ringparam(struct net_device *netdev, | |||
672 | rx_old = adapter->rx_ring; | 669 | rx_old = adapter->rx_ring; |
673 | 670 | ||
674 | err = -ENOMEM; | 671 | err = -ENOMEM; |
675 | txdr = kzalloc(tx_ring_size, GFP_KERNEL); | 672 | txdr = kcalloc(adapter->num_tx_queues, sizeof(struct e1000_tx_ring), GFP_KERNEL); |
676 | if (!txdr) | 673 | if (!txdr) |
677 | goto err_alloc_tx; | 674 | goto err_alloc_tx; |
678 | 675 | ||
679 | rxdr = kzalloc(rx_ring_size, GFP_KERNEL); | 676 | rxdr = kcalloc(adapter->num_rx_queues, sizeof(struct e1000_rx_ring), GFP_KERNEL); |
680 | if (!rxdr) | 677 | if (!rxdr) |
681 | goto err_alloc_rx; | 678 | goto err_alloc_rx; |
682 | 679 | ||
@@ -686,12 +683,12 @@ e1000_set_ringparam(struct net_device *netdev, | |||
686 | rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); | 683 | rxdr->count = max(ring->rx_pending,(uint32_t)E1000_MIN_RXD); |
687 | rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? | 684 | rxdr->count = min(rxdr->count,(uint32_t)(mac_type < e1000_82544 ? |
688 | E1000_MAX_RXD : E1000_MAX_82544_RXD)); | 685 | E1000_MAX_RXD : E1000_MAX_82544_RXD)); |
689 | E1000_ROUNDUP(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); | 686 | rxdr->count = ALIGN(rxdr->count, REQ_RX_DESCRIPTOR_MULTIPLE); |
690 | 687 | ||
691 | txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD); | 688 | txdr->count = max(ring->tx_pending,(uint32_t)E1000_MIN_TXD); |
692 | txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ? | 689 | txdr->count = min(txdr->count,(uint32_t)(mac_type < e1000_82544 ? |
693 | E1000_MAX_TXD : E1000_MAX_82544_TXD)); | 690 | E1000_MAX_TXD : E1000_MAX_82544_TXD)); |
694 | E1000_ROUNDUP(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); | 691 | txdr->count = ALIGN(txdr->count, REQ_TX_DESCRIPTOR_MULTIPLE); |
695 | 692 | ||
696 | for (i = 0; i < adapter->num_tx_queues; i++) | 693 | for (i = 0; i < adapter->num_tx_queues; i++) |
697 | txdr[i].count = txdr->count; | 694 | txdr[i].count = txdr->count; |
@@ -742,7 +739,7 @@ err_setup: | |||
742 | uint32_t pat, value; \ | 739 | uint32_t pat, value; \ |
743 | uint32_t test[] = \ | 740 | uint32_t test[] = \ |
744 | {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ | 741 | {0x5A5A5A5A, 0xA5A5A5A5, 0x00000000, 0xFFFFFFFF}; \ |
745 | for (pat = 0; pat < sizeof(test)/sizeof(test[0]); pat++) { \ | 742 | for (pat = 0; pat < ARRAY_SIZE(test); pat++) { \ |
746 | E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ | 743 | E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \ |
747 | value = E1000_READ_REG(&adapter->hw, R); \ | 744 | value = E1000_READ_REG(&adapter->hw, R); \ |
748 | if (value != (test[pat] & W & M)) { \ | 745 | if (value != (test[pat] & W & M)) { \ |
@@ -1053,23 +1050,24 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) | |||
1053 | struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; | 1050 | struct e1000_rx_ring *rxdr = &adapter->test_rx_ring; |
1054 | struct pci_dev *pdev = adapter->pdev; | 1051 | struct pci_dev *pdev = adapter->pdev; |
1055 | uint32_t rctl; | 1052 | uint32_t rctl; |
1056 | int size, i, ret_val; | 1053 | int i, ret_val; |
1057 | 1054 | ||
1058 | /* Setup Tx descriptor ring and Tx buffers */ | 1055 | /* Setup Tx descriptor ring and Tx buffers */ |
1059 | 1056 | ||
1060 | if (!txdr->count) | 1057 | if (!txdr->count) |
1061 | txdr->count = E1000_DEFAULT_TXD; | 1058 | txdr->count = E1000_DEFAULT_TXD; |
1062 | 1059 | ||
1063 | size = txdr->count * sizeof(struct e1000_buffer); | 1060 | if (!(txdr->buffer_info = kcalloc(txdr->count, |
1064 | if (!(txdr->buffer_info = kmalloc(size, GFP_KERNEL))) { | 1061 | sizeof(struct e1000_buffer), |
1062 | GFP_KERNEL))) { | ||
1065 | ret_val = 1; | 1063 | ret_val = 1; |
1066 | goto err_nomem; | 1064 | goto err_nomem; |
1067 | } | 1065 | } |
1068 | memset(txdr->buffer_info, 0, size); | ||
1069 | 1066 | ||
1070 | txdr->size = txdr->count * sizeof(struct e1000_tx_desc); | 1067 | txdr->size = txdr->count * sizeof(struct e1000_tx_desc); |
1071 | E1000_ROUNDUP(txdr->size, 4096); | 1068 | txdr->size = ALIGN(txdr->size, 4096); |
1072 | if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma))) { | 1069 | if (!(txdr->desc = pci_alloc_consistent(pdev, txdr->size, |
1070 | &txdr->dma))) { | ||
1073 | ret_val = 2; | 1071 | ret_val = 2; |
1074 | goto err_nomem; | 1072 | goto err_nomem; |
1075 | } | 1073 | } |
@@ -1116,12 +1114,12 @@ e1000_setup_desc_rings(struct e1000_adapter *adapter) | |||
1116 | if (!rxdr->count) | 1114 | if (!rxdr->count) |
1117 | rxdr->count = E1000_DEFAULT_RXD; | 1115 | rxdr->count = E1000_DEFAULT_RXD; |
1118 | 1116 | ||
1119 | size = rxdr->count * sizeof(struct e1000_buffer); | 1117 | if (!(rxdr->buffer_info = kcalloc(rxdr->count, |
1120 | if (!(rxdr->buffer_info = kmalloc(size, GFP_KERNEL))) { | 1118 | sizeof(struct e1000_buffer), |
1119 | GFP_KERNEL))) { | ||
1121 | ret_val = 4; | 1120 | ret_val = 4; |
1122 | goto err_nomem; | 1121 | goto err_nomem; |
1123 | } | 1122 | } |
1124 | memset(rxdr->buffer_info, 0, size); | ||
1125 | 1123 | ||
1126 | rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); | 1124 | rxdr->size = rxdr->count * sizeof(struct e1000_rx_desc); |
1127 | if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { | 1125 | if (!(rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma))) { |
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 9267f16b1b32..3a03a74c0609 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c | |||
@@ -748,9 +748,9 @@ e1000_reset(struct e1000_adapter *adapter) | |||
748 | VLAN_TAG_SIZE; | 748 | VLAN_TAG_SIZE; |
749 | min_tx_space = min_rx_space; | 749 | min_tx_space = min_rx_space; |
750 | min_tx_space *= 2; | 750 | min_tx_space *= 2; |
751 | E1000_ROUNDUP(min_tx_space, 1024); | 751 | min_tx_space = ALIGN(min_tx_space, 1024); |
752 | min_tx_space >>= 10; | 752 | min_tx_space >>= 10; |
753 | E1000_ROUNDUP(min_rx_space, 1024); | 753 | min_rx_space = ALIGN(min_rx_space, 1024); |
754 | min_rx_space >>= 10; | 754 | min_rx_space >>= 10; |
755 | 755 | ||
756 | /* If current Tx allocation is less than the min Tx FIFO size, | 756 | /* If current Tx allocation is less than the min Tx FIFO size, |
@@ -1354,31 +1354,27 @@ e1000_sw_init(struct e1000_adapter *adapter) | |||
1354 | static int __devinit | 1354 | static int __devinit |
1355 | e1000_alloc_queues(struct e1000_adapter *adapter) | 1355 | e1000_alloc_queues(struct e1000_adapter *adapter) |
1356 | { | 1356 | { |
1357 | int size; | 1357 | adapter->tx_ring = kcalloc(adapter->num_tx_queues, |
1358 | 1358 | sizeof(struct e1000_tx_ring), GFP_KERNEL); | |
1359 | size = sizeof(struct e1000_tx_ring) * adapter->num_tx_queues; | ||
1360 | adapter->tx_ring = kmalloc(size, GFP_KERNEL); | ||
1361 | if (!adapter->tx_ring) | 1359 | if (!adapter->tx_ring) |
1362 | return -ENOMEM; | 1360 | return -ENOMEM; |
1363 | memset(adapter->tx_ring, 0, size); | ||
1364 | 1361 | ||
1365 | size = sizeof(struct e1000_rx_ring) * adapter->num_rx_queues; | 1362 | adapter->rx_ring = kcalloc(adapter->num_rx_queues, |
1366 | adapter->rx_ring = kmalloc(size, GFP_KERNEL); | 1363 | sizeof(struct e1000_rx_ring), GFP_KERNEL); |
1367 | if (!adapter->rx_ring) { | 1364 | if (!adapter->rx_ring) { |
1368 | kfree(adapter->tx_ring); | 1365 | kfree(adapter->tx_ring); |
1369 | return -ENOMEM; | 1366 | return -ENOMEM; |
1370 | } | 1367 | } |
1371 | memset(adapter->rx_ring, 0, size); | ||
1372 | 1368 | ||
1373 | #ifdef CONFIG_E1000_NAPI | 1369 | #ifdef CONFIG_E1000_NAPI |
1374 | size = sizeof(struct net_device) * adapter->num_rx_queues; | 1370 | adapter->polling_netdev = kcalloc(adapter->num_rx_queues, |
1375 | adapter->polling_netdev = kmalloc(size, GFP_KERNEL); | 1371 | sizeof(struct net_device), |
1372 | GFP_KERNEL); | ||
1376 | if (!adapter->polling_netdev) { | 1373 | if (!adapter->polling_netdev) { |
1377 | kfree(adapter->tx_ring); | 1374 | kfree(adapter->tx_ring); |
1378 | kfree(adapter->rx_ring); | 1375 | kfree(adapter->rx_ring); |
1379 | return -ENOMEM; | 1376 | return -ENOMEM; |
1380 | } | 1377 | } |
1381 | memset(adapter->polling_netdev, 0, size); | ||
1382 | #endif | 1378 | #endif |
1383 | 1379 | ||
1384 | return E1000_SUCCESS; | 1380 | return E1000_SUCCESS; |
@@ -1560,7 +1556,7 @@ e1000_setup_tx_resources(struct e1000_adapter *adapter, | |||
1560 | /* round up to nearest 4K */ | 1556 | /* round up to nearest 4K */ |
1561 | 1557 | ||
1562 | txdr->size = txdr->count * sizeof(struct e1000_tx_desc); | 1558 | txdr->size = txdr->count * sizeof(struct e1000_tx_desc); |
1563 | E1000_ROUNDUP(txdr->size, 4096); | 1559 | txdr->size = ALIGN(txdr->size, 4096); |
1564 | 1560 | ||
1565 | txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); | 1561 | txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); |
1566 | if (!txdr->desc) { | 1562 | if (!txdr->desc) { |
@@ -1774,18 +1770,18 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, | |||
1774 | } | 1770 | } |
1775 | memset(rxdr->buffer_info, 0, size); | 1771 | memset(rxdr->buffer_info, 0, size); |
1776 | 1772 | ||
1777 | size = sizeof(struct e1000_ps_page) * rxdr->count; | 1773 | rxdr->ps_page = kcalloc(rxdr->count, sizeof(struct e1000_ps_page), |
1778 | rxdr->ps_page = kmalloc(size, GFP_KERNEL); | 1774 | GFP_KERNEL); |
1779 | if (!rxdr->ps_page) { | 1775 | if (!rxdr->ps_page) { |
1780 | vfree(rxdr->buffer_info); | 1776 | vfree(rxdr->buffer_info); |
1781 | DPRINTK(PROBE, ERR, | 1777 | DPRINTK(PROBE, ERR, |
1782 | "Unable to allocate memory for the receive descriptor ring\n"); | 1778 | "Unable to allocate memory for the receive descriptor ring\n"); |
1783 | return -ENOMEM; | 1779 | return -ENOMEM; |
1784 | } | 1780 | } |
1785 | memset(rxdr->ps_page, 0, size); | ||
1786 | 1781 | ||
1787 | size = sizeof(struct e1000_ps_page_dma) * rxdr->count; | 1782 | rxdr->ps_page_dma = kcalloc(rxdr->count, |
1788 | rxdr->ps_page_dma = kmalloc(size, GFP_KERNEL); | 1783 | sizeof(struct e1000_ps_page_dma), |
1784 | GFP_KERNEL); | ||
1789 | if (!rxdr->ps_page_dma) { | 1785 | if (!rxdr->ps_page_dma) { |
1790 | vfree(rxdr->buffer_info); | 1786 | vfree(rxdr->buffer_info); |
1791 | kfree(rxdr->ps_page); | 1787 | kfree(rxdr->ps_page); |
@@ -1793,7 +1789,6 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, | |||
1793 | "Unable to allocate memory for the receive descriptor ring\n"); | 1789 | "Unable to allocate memory for the receive descriptor ring\n"); |
1794 | return -ENOMEM; | 1790 | return -ENOMEM; |
1795 | } | 1791 | } |
1796 | memset(rxdr->ps_page_dma, 0, size); | ||
1797 | 1792 | ||
1798 | if (adapter->hw.mac_type <= e1000_82547_rev_2) | 1793 | if (adapter->hw.mac_type <= e1000_82547_rev_2) |
1799 | desc_len = sizeof(struct e1000_rx_desc); | 1794 | desc_len = sizeof(struct e1000_rx_desc); |
@@ -1803,7 +1798,7 @@ e1000_setup_rx_resources(struct e1000_adapter *adapter, | |||
1803 | /* Round up to nearest 4K */ | 1798 | /* Round up to nearest 4K */ |
1804 | 1799 | ||
1805 | rxdr->size = rxdr->count * desc_len; | 1800 | rxdr->size = rxdr->count * desc_len; |
1806 | E1000_ROUNDUP(rxdr->size, 4096); | 1801 | rxdr->size = ALIGN(rxdr->size, 4096); |
1807 | 1802 | ||
1808 | rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); | 1803 | rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); |
1809 | 1804 | ||
@@ -2667,7 +2662,7 @@ e1000_watchdog(unsigned long data) | |||
2667 | 2662 | ||
2668 | netif_carrier_on(netdev); | 2663 | netif_carrier_on(netdev); |
2669 | netif_wake_queue(netdev); | 2664 | netif_wake_queue(netdev); |
2670 | mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); | 2665 | mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); |
2671 | adapter->smartspeed = 0; | 2666 | adapter->smartspeed = 0; |
2672 | } else { | 2667 | } else { |
2673 | /* make sure the receive unit is started */ | 2668 | /* make sure the receive unit is started */ |
@@ -2684,7 +2679,7 @@ e1000_watchdog(unsigned long data) | |||
2684 | DPRINTK(LINK, INFO, "NIC Link is Down\n"); | 2679 | DPRINTK(LINK, INFO, "NIC Link is Down\n"); |
2685 | netif_carrier_off(netdev); | 2680 | netif_carrier_off(netdev); |
2686 | netif_stop_queue(netdev); | 2681 | netif_stop_queue(netdev); |
2687 | mod_timer(&adapter->phy_info_timer, jiffies + 2 * HZ); | 2682 | mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); |
2688 | 2683 | ||
2689 | /* 80003ES2LAN workaround-- | 2684 | /* 80003ES2LAN workaround-- |
2690 | * For packet buffer work-around on link down event; | 2685 | * For packet buffer work-around on link down event; |
@@ -2736,7 +2731,7 @@ e1000_watchdog(unsigned long data) | |||
2736 | e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); | 2731 | e1000_rar_set(&adapter->hw, adapter->hw.mac_addr, 0); |
2737 | 2732 | ||
2738 | /* Reset the timer */ | 2733 | /* Reset the timer */ |
2739 | mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); | 2734 | mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 2 * HZ)); |
2740 | } | 2735 | } |
2741 | 2736 | ||
2742 | enum latency_range { | 2737 | enum latency_range { |
@@ -3175,7 +3170,7 @@ e1000_82547_fifo_workaround(struct e1000_adapter *adapter, struct sk_buff *skb) | |||
3175 | uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; | 3170 | uint32_t fifo_space = adapter->tx_fifo_size - adapter->tx_fifo_head; |
3176 | uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR; | 3171 | uint32_t skb_fifo_len = skb->len + E1000_FIFO_HDR; |
3177 | 3172 | ||
3178 | E1000_ROUNDUP(skb_fifo_len, E1000_FIFO_HDR); | 3173 | skb_fifo_len = ALIGN(skb_fifo_len, E1000_FIFO_HDR); |
3179 | 3174 | ||
3180 | if (adapter->link_duplex != HALF_DUPLEX) | 3175 | if (adapter->link_duplex != HALF_DUPLEX) |
3181 | goto no_fifo_stall_required; | 3176 | goto no_fifo_stall_required; |
diff --git a/drivers/net/e1000/e1000_param.c b/drivers/net/e1000/e1000_param.c index f8862e203ac9..f485874a63f5 100644 --- a/drivers/net/e1000/e1000_param.c +++ b/drivers/net/e1000/e1000_param.c | |||
@@ -305,7 +305,7 @@ e1000_check_options(struct e1000_adapter *adapter) | |||
305 | if (num_TxDescriptors > bd) { | 305 | if (num_TxDescriptors > bd) { |
306 | tx_ring->count = TxDescriptors[bd]; | 306 | tx_ring->count = TxDescriptors[bd]; |
307 | e1000_validate_option(&tx_ring->count, &opt, adapter); | 307 | e1000_validate_option(&tx_ring->count, &opt, adapter); |
308 | E1000_ROUNDUP(tx_ring->count, | 308 | tx_ring->count = ALIGN(tx_ring->count, |
309 | REQ_TX_DESCRIPTOR_MULTIPLE); | 309 | REQ_TX_DESCRIPTOR_MULTIPLE); |
310 | } else { | 310 | } else { |
311 | tx_ring->count = opt.def; | 311 | tx_ring->count = opt.def; |
@@ -331,7 +331,7 @@ e1000_check_options(struct e1000_adapter *adapter) | |||
331 | if (num_RxDescriptors > bd) { | 331 | if (num_RxDescriptors > bd) { |
332 | rx_ring->count = RxDescriptors[bd]; | 332 | rx_ring->count = RxDescriptors[bd]; |
333 | e1000_validate_option(&rx_ring->count, &opt, adapter); | 333 | e1000_validate_option(&rx_ring->count, &opt, adapter); |
334 | E1000_ROUNDUP(rx_ring->count, | 334 | rx_ring->count = ALIGN(rx_ring->count, |
335 | REQ_RX_DESCRIPTOR_MULTIPLE); | 335 | REQ_RX_DESCRIPTOR_MULTIPLE); |
336 | } else { | 336 | } else { |
337 | rx_ring->count = opt.def; | 337 | rx_ring->count = opt.def; |
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index 8aaf5ec0c360..7934ea37f944 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c | |||
@@ -115,6 +115,7 @@ | |||
115 | #include <linux/mca-legacy.h> | 115 | #include <linux/mca-legacy.h> |
116 | #include <linux/spinlock.h> | 116 | #include <linux/spinlock.h> |
117 | #include <linux/bitops.h> | 117 | #include <linux/bitops.h> |
118 | #include <linux/jiffies.h> | ||
118 | 119 | ||
119 | #include <asm/system.h> | 120 | #include <asm/system.h> |
120 | #include <asm/io.h> | 121 | #include <asm/io.h> |
@@ -556,7 +557,7 @@ static void unstick_cu(struct net_device *dev) | |||
556 | 557 | ||
557 | if (lp->started) | 558 | if (lp->started) |
558 | { | 559 | { |
559 | if ((jiffies - dev->trans_start)>50) | 560 | if (time_after(jiffies, dev->trans_start + 50)) |
560 | { | 561 | { |
561 | if (lp->tx_link==lp->last_tx_restart) | 562 | if (lp->tx_link==lp->last_tx_restart) |
562 | { | 563 | { |
@@ -612,7 +613,7 @@ static void unstick_cu(struct net_device *dev) | |||
612 | } | 613 | } |
613 | else | 614 | else |
614 | { | 615 | { |
615 | if ((jiffies-lp->init_time)>10) | 616 | if (time_after(jiffies, lp->init_time + 10)) |
616 | { | 617 | { |
617 | unsigned short status = scb_status(dev); | 618 | unsigned short status = scb_status(dev); |
618 | printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n", | 619 | printk(KERN_WARNING "%s: i82586 startup timed out, status %04x, resetting...\n", |
@@ -776,7 +777,7 @@ static unsigned short eexp_start_irq(struct net_device *dev, | |||
776 | static void eexp_cmd_clear(struct net_device *dev) | 777 | static void eexp_cmd_clear(struct net_device *dev) |
777 | { | 778 | { |
778 | unsigned long int oldtime = jiffies; | 779 | unsigned long int oldtime = jiffies; |
779 | while (scb_rdcmd(dev) && ((jiffies-oldtime)<10)); | 780 | while (scb_rdcmd(dev) && (time_before(jiffies, oldtime + 10))); |
780 | if (scb_rdcmd(dev)) { | 781 | if (scb_rdcmd(dev)) { |
781 | printk("%s: command didn't clear\n", dev->name); | 782 | printk("%s: command didn't clear\n", dev->name); |
782 | } | 783 | } |
@@ -1649,7 +1650,7 @@ eexp_set_multicast(struct net_device *dev) | |||
1649 | #endif | 1650 | #endif |
1650 | oj = jiffies; | 1651 | oj = jiffies; |
1651 | while ((SCB_CUstat(scb_status(dev)) == 2) && | 1652 | while ((SCB_CUstat(scb_status(dev)) == 2) && |
1652 | ((jiffies-oj) < 2000)); | 1653 | (time_before(jiffies, oj + 2000))); |
1653 | if (SCB_CUstat(scb_status(dev)) == 2) | 1654 | if (SCB_CUstat(scb_status(dev)) == 2) |
1654 | printk("%s: warning, CU didn't stop\n", dev->name); | 1655 | printk("%s: warning, CU didn't stop\n", dev->name); |
1655 | lp->started &= ~(STARTED_CU); | 1656 | lp->started &= ~(STARTED_CU); |
diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 42295d61ecd8..602872dbe15f 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h | |||
@@ -39,7 +39,7 @@ | |||
39 | #include <asm/io.h> | 39 | #include <asm/io.h> |
40 | 40 | ||
41 | #define DRV_NAME "ehea" | 41 | #define DRV_NAME "ehea" |
42 | #define DRV_VERSION "EHEA_0046" | 42 | #define DRV_VERSION "EHEA_0058" |
43 | 43 | ||
44 | #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ | 44 | #define EHEA_MSG_DEFAULT (NETIF_MSG_LINK | NETIF_MSG_TIMER \ |
45 | | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) | 45 | | NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR) |
@@ -78,10 +78,7 @@ | |||
78 | #define EHEA_RQ2_PKT_SIZE 1522 | 78 | #define EHEA_RQ2_PKT_SIZE 1522 |
79 | #define EHEA_L_PKT_SIZE 256 /* low latency */ | 79 | #define EHEA_L_PKT_SIZE 256 /* low latency */ |
80 | 80 | ||
81 | #define EHEA_POLL_MAX_RWQE 1000 | ||
82 | |||
83 | /* Send completion signaling */ | 81 | /* Send completion signaling */ |
84 | #define EHEA_SIG_IV_LONG 1 | ||
85 | 82 | ||
86 | /* Protection Domain Identifier */ | 83 | /* Protection Domain Identifier */ |
87 | #define EHEA_PD_ID 0xaabcdeff | 84 | #define EHEA_PD_ID 0xaabcdeff |
@@ -108,11 +105,7 @@ | |||
108 | #define EHEA_CACHE_LINE 128 | 105 | #define EHEA_CACHE_LINE 128 |
109 | 106 | ||
110 | /* Memory Regions */ | 107 | /* Memory Regions */ |
111 | #define EHEA_MR_MAX_TX_PAGES 20 | ||
112 | #define EHEA_MR_TX_DATA_PN 3 | ||
113 | #define EHEA_MR_ACC_CTRL 0x00800000 | 108 | #define EHEA_MR_ACC_CTRL 0x00800000 |
114 | #define EHEA_RWQES_PER_MR_RQ2 10 | ||
115 | #define EHEA_RWQES_PER_MR_RQ3 10 | ||
116 | 109 | ||
117 | #define EHEA_WATCH_DOG_TIMEOUT 10*HZ | 110 | #define EHEA_WATCH_DOG_TIMEOUT 10*HZ |
118 | 111 | ||
@@ -311,6 +304,7 @@ struct ehea_cq { | |||
311 | * Memory Region | 304 | * Memory Region |
312 | */ | 305 | */ |
313 | struct ehea_mr { | 306 | struct ehea_mr { |
307 | struct ehea_adapter *adapter; | ||
314 | u64 handle; | 308 | u64 handle; |
315 | u64 vaddr; | 309 | u64 vaddr; |
316 | u32 lkey; | 310 | u32 lkey; |
@@ -319,17 +313,12 @@ struct ehea_mr { | |||
319 | /* | 313 | /* |
320 | * Port state information | 314 | * Port state information |
321 | */ | 315 | */ |
322 | struct port_state { | 316 | struct port_stats { |
323 | int poll_max_processed; | ||
324 | int poll_receive_errors; | 317 | int poll_receive_errors; |
325 | int ehea_poll; | ||
326 | int queue_stopped; | 318 | int queue_stopped; |
327 | int min_swqe_avail; | 319 | int err_tcp_cksum; |
328 | u64 sqc_stop_sum; | 320 | int err_ip_cksum; |
329 | int pkt_send; | 321 | int err_frame_crc; |
330 | int pkt_xmit; | ||
331 | int send_tasklet; | ||
332 | int nwqe; | ||
333 | }; | 322 | }; |
334 | 323 | ||
335 | #define EHEA_IRQ_NAME_SIZE 20 | 324 | #define EHEA_IRQ_NAME_SIZE 20 |
@@ -348,6 +337,7 @@ struct ehea_q_skb_arr { | |||
348 | * Port resources | 337 | * Port resources |
349 | */ | 338 | */ |
350 | struct ehea_port_res { | 339 | struct ehea_port_res { |
340 | struct port_stats p_stats; | ||
351 | struct ehea_mr send_mr; /* send memory region */ | 341 | struct ehea_mr send_mr; /* send memory region */ |
352 | struct ehea_mr recv_mr; /* receive memory region */ | 342 | struct ehea_mr recv_mr; /* receive memory region */ |
353 | spinlock_t xmit_lock; | 343 | spinlock_t xmit_lock; |
@@ -357,9 +347,8 @@ struct ehea_port_res { | |||
357 | struct ehea_qp *qp; | 347 | struct ehea_qp *qp; |
358 | struct ehea_cq *send_cq; | 348 | struct ehea_cq *send_cq; |
359 | struct ehea_cq *recv_cq; | 349 | struct ehea_cq *recv_cq; |
360 | struct ehea_eq *send_eq; | 350 | struct ehea_eq *eq; |
361 | struct ehea_eq *recv_eq; | 351 | struct net_device *d_netdev; |
362 | spinlock_t send_lock; | ||
363 | struct ehea_q_skb_arr rq1_skba; | 352 | struct ehea_q_skb_arr rq1_skba; |
364 | struct ehea_q_skb_arr rq2_skba; | 353 | struct ehea_q_skb_arr rq2_skba; |
365 | struct ehea_q_skb_arr rq3_skba; | 354 | struct ehea_q_skb_arr rq3_skba; |
@@ -369,21 +358,18 @@ struct ehea_port_res { | |||
369 | int swqe_refill_th; | 358 | int swqe_refill_th; |
370 | atomic_t swqe_avail; | 359 | atomic_t swqe_avail; |
371 | int swqe_ll_count; | 360 | int swqe_ll_count; |
372 | int swqe_count; | ||
373 | u32 swqe_id_counter; | 361 | u32 swqe_id_counter; |
374 | u64 tx_packets; | 362 | u64 tx_packets; |
375 | struct tasklet_struct send_comp_task; | ||
376 | spinlock_t recv_lock; | ||
377 | struct port_state p_state; | ||
378 | u64 rx_packets; | 363 | u64 rx_packets; |
379 | u32 poll_counter; | 364 | u32 poll_counter; |
380 | }; | 365 | }; |
381 | 366 | ||
382 | 367 | ||
368 | #define EHEA_MAX_PORTS 16 | ||
383 | struct ehea_adapter { | 369 | struct ehea_adapter { |
384 | u64 handle; | 370 | u64 handle; |
385 | u8 num_ports; | 371 | struct ibmebus_dev *ebus_dev; |
386 | struct ehea_port *port[16]; | 372 | struct ehea_port *port[EHEA_MAX_PORTS]; |
387 | struct ehea_eq *neq; /* notification event queue */ | 373 | struct ehea_eq *neq; /* notification event queue */ |
388 | struct workqueue_struct *ehea_wq; | 374 | struct workqueue_struct *ehea_wq; |
389 | struct tasklet_struct neq_tasklet; | 375 | struct tasklet_struct neq_tasklet; |
@@ -406,7 +392,7 @@ struct ehea_port { | |||
406 | struct net_device *netdev; | 392 | struct net_device *netdev; |
407 | struct net_device_stats stats; | 393 | struct net_device_stats stats; |
408 | struct ehea_port_res port_res[EHEA_MAX_PORT_RES]; | 394 | struct ehea_port_res port_res[EHEA_MAX_PORT_RES]; |
409 | struct device_node *of_dev_node; /* Open Firmware Device Node */ | 395 | struct of_device ofdev; /* Open Firmware Device */ |
410 | struct ehea_mc_list *mc_list; /* Multicast MAC addresses */ | 396 | struct ehea_mc_list *mc_list; /* Multicast MAC addresses */ |
411 | struct vlan_group *vgrp; | 397 | struct vlan_group *vgrp; |
412 | struct ehea_eq *qp_eq; | 398 | struct ehea_eq *qp_eq; |
@@ -415,7 +401,9 @@ struct ehea_port { | |||
415 | char int_aff_name[EHEA_IRQ_NAME_SIZE]; | 401 | char int_aff_name[EHEA_IRQ_NAME_SIZE]; |
416 | int allmulti; /* Indicates IFF_ALLMULTI state */ | 402 | int allmulti; /* Indicates IFF_ALLMULTI state */ |
417 | int promisc; /* Indicates IFF_PROMISC state */ | 403 | int promisc; /* Indicates IFF_PROMISC state */ |
404 | int num_tx_qps; | ||
418 | int num_add_tx_qps; | 405 | int num_add_tx_qps; |
406 | int num_mcs; | ||
419 | int resets; | 407 | int resets; |
420 | u64 mac_addr; | 408 | u64 mac_addr; |
421 | u32 logical_port_id; | 409 | u32 logical_port_id; |
diff --git a/drivers/net/ehea/ehea_ethtool.c b/drivers/net/ehea/ehea_ethtool.c index 9f57c2e78ced..decec8cfe96b 100644 --- a/drivers/net/ehea/ehea_ethtool.c +++ b/drivers/net/ehea/ehea_ethtool.c | |||
@@ -144,8 +144,8 @@ static int ehea_nway_reset(struct net_device *dev) | |||
144 | static void ehea_get_drvinfo(struct net_device *dev, | 144 | static void ehea_get_drvinfo(struct net_device *dev, |
145 | struct ethtool_drvinfo *info) | 145 | struct ethtool_drvinfo *info) |
146 | { | 146 | { |
147 | strlcpy(info->driver, DRV_NAME, sizeof(info->driver) - 1); | 147 | strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); |
148 | strlcpy(info->version, DRV_VERSION, sizeof(info->version) - 1); | 148 | strlcpy(info->version, DRV_VERSION, sizeof(info->version)); |
149 | } | 149 | } |
150 | 150 | ||
151 | static u32 ehea_get_msglevel(struct net_device *dev) | 151 | static u32 ehea_get_msglevel(struct net_device *dev) |
@@ -166,33 +166,23 @@ static u32 ehea_get_rx_csum(struct net_device *dev) | |||
166 | } | 166 | } |
167 | 167 | ||
168 | static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { | 168 | static char ehea_ethtool_stats_keys[][ETH_GSTRING_LEN] = { |
169 | {"poll_max_processed"}, | ||
170 | {"queue_stopped"}, | ||
171 | {"min_swqe_avail"}, | ||
172 | {"poll_receive_err"}, | ||
173 | {"pkt_send"}, | ||
174 | {"pkt_xmit"}, | ||
175 | {"send_tasklet"}, | ||
176 | {"ehea_poll"}, | ||
177 | {"nwqe"}, | ||
178 | {"swqe_available_0"}, | ||
179 | {"sig_comp_iv"}, | 169 | {"sig_comp_iv"}, |
180 | {"swqe_refill_th"}, | 170 | {"swqe_refill_th"}, |
181 | {"port resets"}, | 171 | {"port resets"}, |
182 | {"rxo"}, | 172 | {"Receive errors"}, |
183 | {"rx64"}, | 173 | {"TCP cksum errors"}, |
184 | {"rx65"}, | 174 | {"IP cksum errors"}, |
185 | {"rx128"}, | 175 | {"Frame cksum errors"}, |
186 | {"rx256"}, | 176 | {"num SQ stopped"}, |
187 | {"rx512"}, | 177 | {"SQ stopped"}, |
188 | {"rx1024"}, | 178 | {"PR0 free_swqes"}, |
189 | {"txo"}, | 179 | {"PR1 free_swqes"}, |
190 | {"tx64"}, | 180 | {"PR2 free_swqes"}, |
191 | {"tx65"}, | 181 | {"PR3 free_swqes"}, |
192 | {"tx128"}, | 182 | {"PR4 free_swqes"}, |
193 | {"tx256"}, | 183 | {"PR5 free_swqes"}, |
194 | {"tx512"}, | 184 | {"PR6 free_swqes"}, |
195 | {"tx1024"}, | 185 | {"PR7 free_swqes"}, |
196 | }; | 186 | }; |
197 | 187 | ||
198 | static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) | 188 | static void ehea_get_strings(struct net_device *dev, u32 stringset, u8 *data) |
@@ -211,63 +201,44 @@ static int ehea_get_stats_count(struct net_device *dev) | |||
211 | static void ehea_get_ethtool_stats(struct net_device *dev, | 201 | static void ehea_get_ethtool_stats(struct net_device *dev, |
212 | struct ethtool_stats *stats, u64 *data) | 202 | struct ethtool_stats *stats, u64 *data) |
213 | { | 203 | { |
214 | u64 hret; | 204 | int i, k, tmp; |
215 | int i; | ||
216 | struct ehea_port *port = netdev_priv(dev); | 205 | struct ehea_port *port = netdev_priv(dev); |
217 | struct ehea_adapter *adapter = port->adapter; | ||
218 | struct ehea_port_res *pr = &port->port_res[0]; | ||
219 | struct port_state *p_state = &pr->p_state; | ||
220 | struct hcp_ehea_port_cb6 *cb6; | ||
221 | 206 | ||
222 | for (i = 0; i < ehea_get_stats_count(dev); i++) | 207 | for (i = 0; i < ehea_get_stats_count(dev); i++) |
223 | data[i] = 0; | 208 | data[i] = 0; |
224 | |||
225 | i = 0; | 209 | i = 0; |
226 | 210 | ||
227 | data[i++] = p_state->poll_max_processed; | ||
228 | data[i++] = p_state->queue_stopped; | ||
229 | data[i++] = p_state->min_swqe_avail; | ||
230 | data[i++] = p_state->poll_receive_errors; | ||
231 | data[i++] = p_state->pkt_send; | ||
232 | data[i++] = p_state->pkt_xmit; | ||
233 | data[i++] = p_state->send_tasklet; | ||
234 | data[i++] = p_state->ehea_poll; | ||
235 | data[i++] = p_state->nwqe; | ||
236 | data[i++] = atomic_read(&port->port_res[0].swqe_avail); | ||
237 | data[i++] = port->sig_comp_iv; | 211 | data[i++] = port->sig_comp_iv; |
238 | data[i++] = port->port_res[0].swqe_refill_th; | 212 | data[i++] = port->port_res[0].swqe_refill_th; |
239 | data[i++] = port->resets; | 213 | data[i++] = port->resets; |
240 | 214 | ||
241 | cb6 = kzalloc(PAGE_SIZE, GFP_KERNEL); | 215 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) |
242 | if (!cb6) { | 216 | tmp += port->port_res[k].p_stats.poll_receive_errors; |
243 | ehea_error("no mem for cb6"); | 217 | data[i++] = tmp; |
244 | return; | 218 | |
245 | } | 219 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) |
220 | tmp += port->port_res[k].p_stats.err_tcp_cksum; | ||
221 | data[i++] = tmp; | ||
222 | |||
223 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | ||
224 | tmp += port->port_res[k].p_stats.err_ip_cksum; | ||
225 | data[i++] = tmp; | ||
226 | |||
227 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | ||
228 | tmp += port->port_res[k].p_stats.err_frame_crc; | ||
229 | data[i++] = tmp; | ||
230 | |||
231 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | ||
232 | tmp += port->port_res[k].p_stats.queue_stopped; | ||
233 | data[i++] = tmp; | ||
234 | |||
235 | for (k = 0, tmp = 0; k < EHEA_MAX_PORT_RES; k++) | ||
236 | tmp |= port->port_res[k].queue_stopped; | ||
237 | data[i++] = tmp; | ||
238 | |||
239 | for (k = 0; k < 8; k++) | ||
240 | data[i++] = atomic_read(&port->port_res[k].swqe_avail); | ||
246 | 241 | ||
247 | hret = ehea_h_query_ehea_port(adapter->handle, port->logical_port_id, | ||
248 | H_PORT_CB6, H_PORT_CB6_ALL, cb6); | ||
249 | if (netif_msg_hw(port)) | ||
250 | ehea_dump(cb6, sizeof(*cb6), "ehea_get_ethtool_stats"); | ||
251 | |||
252 | if (hret == H_SUCCESS) { | ||
253 | data[i++] = cb6->rxo; | ||
254 | data[i++] = cb6->rx64; | ||
255 | data[i++] = cb6->rx65; | ||
256 | data[i++] = cb6->rx128; | ||
257 | data[i++] = cb6->rx256; | ||
258 | data[i++] = cb6->rx512; | ||
259 | data[i++] = cb6->rx1024; | ||
260 | data[i++] = cb6->txo; | ||
261 | data[i++] = cb6->tx64; | ||
262 | data[i++] = cb6->tx65; | ||
263 | data[i++] = cb6->tx128; | ||
264 | data[i++] = cb6->tx256; | ||
265 | data[i++] = cb6->tx512; | ||
266 | data[i++] = cb6->tx1024; | ||
267 | } else | ||
268 | ehea_error("query_ehea_port failed"); | ||
269 | |||
270 | kfree(cb6); | ||
271 | } | 242 | } |
272 | 243 | ||
273 | const struct ethtool_ops ehea_ethtool_ops = { | 244 | const struct ethtool_ops ehea_ethtool_ops = { |
diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 58364a0ff378..c7a5614e66c0 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c | |||
@@ -51,13 +51,18 @@ static int rq1_entries = EHEA_DEF_ENTRIES_RQ1; | |||
51 | static int rq2_entries = EHEA_DEF_ENTRIES_RQ2; | 51 | static int rq2_entries = EHEA_DEF_ENTRIES_RQ2; |
52 | static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; | 52 | static int rq3_entries = EHEA_DEF_ENTRIES_RQ3; |
53 | static int sq_entries = EHEA_DEF_ENTRIES_SQ; | 53 | static int sq_entries = EHEA_DEF_ENTRIES_SQ; |
54 | static int use_mcs = 0; | ||
55 | static int num_tx_qps = EHEA_NUM_TX_QP; | ||
54 | 56 | ||
55 | module_param(msg_level, int, 0); | 57 | module_param(msg_level, int, 0); |
56 | module_param(rq1_entries, int, 0); | 58 | module_param(rq1_entries, int, 0); |
57 | module_param(rq2_entries, int, 0); | 59 | module_param(rq2_entries, int, 0); |
58 | module_param(rq3_entries, int, 0); | 60 | module_param(rq3_entries, int, 0); |
59 | module_param(sq_entries, int, 0); | 61 | module_param(sq_entries, int, 0); |
62 | module_param(use_mcs, int, 0); | ||
63 | module_param(num_tx_qps, int, 0); | ||
60 | 64 | ||
65 | MODULE_PARM_DESC(num_tx_qps, "Number of TX-QPS"); | ||
61 | MODULE_PARM_DESC(msg_level, "msg_level"); | 66 | MODULE_PARM_DESC(msg_level, "msg_level"); |
62 | MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 " | 67 | MODULE_PARM_DESC(rq3_entries, "Number of entries for Receive Queue 3 " |
63 | "[2^x - 1], x = [6..14]. Default = " | 68 | "[2^x - 1], x = [6..14]. Default = " |
@@ -71,6 +76,29 @@ MODULE_PARM_DESC(rq1_entries, "Number of entries for Receive Queue 1 " | |||
71 | MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " | 76 | MODULE_PARM_DESC(sq_entries, " Number of entries for the Send Queue " |
72 | "[2^x - 1], x = [6..14]. Default = " | 77 | "[2^x - 1], x = [6..14]. Default = " |
73 | __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); | 78 | __MODULE_STRING(EHEA_DEF_ENTRIES_SQ) ")"); |
79 | MODULE_PARM_DESC(use_mcs, " 0:NAPI, 1:Multiple receive queues, Default = 1 "); | ||
80 | |||
81 | static int port_name_cnt = 0; | ||
82 | |||
83 | static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, | ||
84 | const struct of_device_id *id); | ||
85 | |||
86 | static int __devexit ehea_remove(struct ibmebus_dev *dev); | ||
87 | |||
88 | static struct of_device_id ehea_device_table[] = { | ||
89 | { | ||
90 | .name = "lhea", | ||
91 | .compatible = "IBM,lhea", | ||
92 | }, | ||
93 | {}, | ||
94 | }; | ||
95 | |||
96 | static struct ibmebus_driver ehea_driver = { | ||
97 | .name = "ehea", | ||
98 | .id_table = ehea_device_table, | ||
99 | .probe = ehea_probe_adapter, | ||
100 | .remove = ehea_remove, | ||
101 | }; | ||
74 | 102 | ||
75 | void ehea_dump(void *adr, int len, char *msg) { | 103 | void ehea_dump(void *adr, int len, char *msg) { |
76 | int x; | 104 | int x; |
@@ -197,7 +225,7 @@ static int ehea_refill_rq_def(struct ehea_port_res *pr, | |||
197 | struct sk_buff *skb = netdev_alloc_skb(dev, packet_size); | 225 | struct sk_buff *skb = netdev_alloc_skb(dev, packet_size); |
198 | if (!skb) { | 226 | if (!skb) { |
199 | ehea_error("%s: no mem for skb/%d wqes filled", | 227 | ehea_error("%s: no mem for skb/%d wqes filled", |
200 | dev->name, i); | 228 | pr->port->netdev->name, i); |
201 | q_skba->os_skbs = fill_wqes - i; | 229 | q_skba->os_skbs = fill_wqes - i; |
202 | ret = -ENOMEM; | 230 | ret = -ENOMEM; |
203 | break; | 231 | break; |
@@ -321,6 +349,13 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, | |||
321 | { | 349 | { |
322 | struct sk_buff *skb; | 350 | struct sk_buff *skb; |
323 | 351 | ||
352 | if (cqe->status & EHEA_CQE_STAT_ERR_TCP) | ||
353 | pr->p_stats.err_tcp_cksum++; | ||
354 | if (cqe->status & EHEA_CQE_STAT_ERR_IP) | ||
355 | pr->p_stats.err_ip_cksum++; | ||
356 | if (cqe->status & EHEA_CQE_STAT_ERR_CRC) | ||
357 | pr->p_stats.err_frame_crc++; | ||
358 | |||
324 | if (netif_msg_rx_err(pr->port)) { | 359 | if (netif_msg_rx_err(pr->port)) { |
325 | ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr); | 360 | ehea_error("CQE Error for QP %d", pr->qp->init_attr.qp_nr); |
326 | ehea_dump(cqe, sizeof(*cqe), "CQE"); | 361 | ehea_dump(cqe, sizeof(*cqe), "CQE"); |
@@ -345,10 +380,11 @@ static int ehea_treat_poll_error(struct ehea_port_res *pr, int rq, | |||
345 | return 0; | 380 | return 0; |
346 | } | 381 | } |
347 | 382 | ||
348 | static int ehea_poll(struct net_device *dev, int *budget) | 383 | static struct ehea_cqe *ehea_proc_rwqes(struct net_device *dev, |
384 | struct ehea_port_res *pr, | ||
385 | int *budget) | ||
349 | { | 386 | { |
350 | struct ehea_port *port = netdev_priv(dev); | 387 | struct ehea_port *port = pr->port; |
351 | struct ehea_port_res *pr = &port->port_res[0]; | ||
352 | struct ehea_qp *qp = pr->qp; | 388 | struct ehea_qp *qp = pr->qp; |
353 | struct ehea_cqe *cqe; | 389 | struct ehea_cqe *cqe; |
354 | struct sk_buff *skb; | 390 | struct sk_buff *skb; |
@@ -359,14 +395,12 @@ static int ehea_poll(struct net_device *dev, int *budget) | |||
359 | int skb_arr_rq2_len = pr->rq2_skba.len; | 395 | int skb_arr_rq2_len = pr->rq2_skba.len; |
360 | int skb_arr_rq3_len = pr->rq3_skba.len; | 396 | int skb_arr_rq3_len = pr->rq3_skba.len; |
361 | int processed, processed_rq1, processed_rq2, processed_rq3; | 397 | int processed, processed_rq1, processed_rq2, processed_rq3; |
362 | int wqe_index, last_wqe_index, rq, intreq, my_quota, port_reset; | 398 | int wqe_index, last_wqe_index, rq, my_quota, port_reset; |
363 | 399 | ||
364 | processed = processed_rq1 = processed_rq2 = processed_rq3 = 0; | 400 | processed = processed_rq1 = processed_rq2 = processed_rq3 = 0; |
365 | last_wqe_index = 0; | 401 | last_wqe_index = 0; |
366 | my_quota = min(*budget, dev->quota); | 402 | my_quota = min(*budget, dev->quota); |
367 | my_quota = min(my_quota, EHEA_POLL_MAX_RWQE); | ||
368 | 403 | ||
369 | /* rq0 is low latency RQ */ | ||
370 | cqe = ehea_poll_rq1(qp, &wqe_index); | 404 | cqe = ehea_poll_rq1(qp, &wqe_index); |
371 | while ((my_quota > 0) && cqe) { | 405 | while ((my_quota > 0) && cqe) { |
372 | ehea_inc_rq1(qp); | 406 | ehea_inc_rq1(qp); |
@@ -386,7 +420,8 @@ static int ehea_poll(struct net_device *dev, int *budget) | |||
386 | if (unlikely(!skb)) { | 420 | if (unlikely(!skb)) { |
387 | if (netif_msg_rx_err(port)) | 421 | if (netif_msg_rx_err(port)) |
388 | ehea_error("LL rq1: skb=NULL"); | 422 | ehea_error("LL rq1: skb=NULL"); |
389 | skb = netdev_alloc_skb(dev, | 423 | |
424 | skb = netdev_alloc_skb(port->netdev, | ||
390 | EHEA_L_PKT_SIZE); | 425 | EHEA_L_PKT_SIZE); |
391 | if (!skb) | 426 | if (!skb) |
392 | break; | 427 | break; |
@@ -402,7 +437,7 @@ static int ehea_poll(struct net_device *dev, int *budget) | |||
402 | ehea_error("rq2: skb=NULL"); | 437 | ehea_error("rq2: skb=NULL"); |
403 | break; | 438 | break; |
404 | } | 439 | } |
405 | ehea_fill_skb(dev, skb, cqe); | 440 | ehea_fill_skb(port->netdev, skb, cqe); |
406 | processed_rq2++; | 441 | processed_rq2++; |
407 | } else { /* RQ3 */ | 442 | } else { /* RQ3 */ |
408 | skb = get_skb_by_index(skb_arr_rq3, | 443 | skb = get_skb_by_index(skb_arr_rq3, |
@@ -412,7 +447,7 @@ static int ehea_poll(struct net_device *dev, int *budget) | |||
412 | ehea_error("rq3: skb=NULL"); | 447 | ehea_error("rq3: skb=NULL"); |
413 | break; | 448 | break; |
414 | } | 449 | } |
415 | ehea_fill_skb(dev, skb, cqe); | 450 | ehea_fill_skb(port->netdev, skb, cqe); |
416 | processed_rq3++; | 451 | processed_rq3++; |
417 | } | 452 | } |
418 | 453 | ||
@@ -421,9 +456,8 @@ static int ehea_poll(struct net_device *dev, int *budget) | |||
421 | cqe->vlan_tag); | 456 | cqe->vlan_tag); |
422 | else | 457 | else |
423 | netif_receive_skb(skb); | 458 | netif_receive_skb(skb); |
424 | 459 | } else { | |
425 | } else { /* Error occured */ | 460 | pr->p_stats.poll_receive_errors++; |
426 | pr->p_state.poll_receive_errors++; | ||
427 | port_reset = ehea_treat_poll_error(pr, rq, cqe, | 461 | port_reset = ehea_treat_poll_error(pr, rq, cqe, |
428 | &processed_rq2, | 462 | &processed_rq2, |
429 | &processed_rq3); | 463 | &processed_rq3); |
@@ -433,72 +467,32 @@ static int ehea_poll(struct net_device *dev, int *budget) | |||
433 | cqe = ehea_poll_rq1(qp, &wqe_index); | 467 | cqe = ehea_poll_rq1(qp, &wqe_index); |
434 | } | 468 | } |
435 | 469 | ||
436 | dev->quota -= processed; | ||
437 | *budget -= processed; | ||
438 | |||
439 | pr->p_state.ehea_poll += 1; | ||
440 | pr->rx_packets += processed; | 470 | pr->rx_packets += processed; |
471 | *budget -= processed; | ||
441 | 472 | ||
442 | ehea_refill_rq1(pr, last_wqe_index, processed_rq1); | 473 | ehea_refill_rq1(pr, last_wqe_index, processed_rq1); |
443 | ehea_refill_rq2(pr, processed_rq2); | 474 | ehea_refill_rq2(pr, processed_rq2); |
444 | ehea_refill_rq3(pr, processed_rq3); | 475 | ehea_refill_rq3(pr, processed_rq3); |
445 | 476 | ||
446 | intreq = ((pr->p_state.ehea_poll & 0xF) == 0xF); | 477 | cqe = ehea_poll_rq1(qp, &wqe_index); |
447 | 478 | return cqe; | |
448 | if (!cqe || intreq) { | ||
449 | netif_rx_complete(dev); | ||
450 | ehea_reset_cq_ep(pr->recv_cq); | ||
451 | ehea_reset_cq_n1(pr->recv_cq); | ||
452 | cqe = hw_qeit_get_valid(&qp->hw_rqueue1); | ||
453 | if (!cqe || intreq) | ||
454 | return 0; | ||
455 | if (!netif_rx_reschedule(dev, my_quota)) | ||
456 | return 0; | ||
457 | } | ||
458 | return 1; | ||
459 | } | 479 | } |
460 | 480 | ||
461 | void free_sent_skbs(struct ehea_cqe *cqe, struct ehea_port_res *pr) | 481 | static struct ehea_cqe *ehea_proc_cqes(struct ehea_port_res *pr, int my_quota) |
462 | { | 482 | { |
463 | struct sk_buff *skb; | 483 | struct sk_buff *skb; |
464 | int index, max_index_mask, i; | ||
465 | |||
466 | index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id); | ||
467 | max_index_mask = pr->sq_skba.len - 1; | ||
468 | for (i = 0; i < EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); i++) { | ||
469 | skb = pr->sq_skba.arr[index]; | ||
470 | if (likely(skb)) { | ||
471 | dev_kfree_skb(skb); | ||
472 | pr->sq_skba.arr[index] = NULL; | ||
473 | } else { | ||
474 | ehea_error("skb=NULL, wr_id=%lX, loop=%d, index=%d", | ||
475 | cqe->wr_id, i, index); | ||
476 | } | ||
477 | index--; | ||
478 | index &= max_index_mask; | ||
479 | } | ||
480 | } | ||
481 | |||
482 | #define MAX_SENDCOMP_QUOTA 400 | ||
483 | void ehea_send_irq_tasklet(unsigned long data) | ||
484 | { | ||
485 | struct ehea_port_res *pr = (struct ehea_port_res*)data; | ||
486 | struct ehea_cq *send_cq = pr->send_cq; | 484 | struct ehea_cq *send_cq = pr->send_cq; |
487 | struct ehea_cqe *cqe; | 485 | struct ehea_cqe *cqe; |
488 | int quota = MAX_SENDCOMP_QUOTA; | 486 | int quota = my_quota; |
489 | int cqe_counter = 0; | 487 | int cqe_counter = 0; |
490 | int swqe_av = 0; | 488 | int swqe_av = 0; |
489 | int index; | ||
491 | unsigned long flags; | 490 | unsigned long flags; |
492 | 491 | ||
493 | do { | 492 | cqe = ehea_poll_cq(send_cq); |
494 | cqe = ehea_poll_cq(send_cq); | 493 | while(cqe && (quota > 0)) { |
495 | if (!cqe) { | 494 | ehea_inc_cq(send_cq); |
496 | ehea_reset_cq_ep(send_cq); | 495 | |
497 | ehea_reset_cq_n1(send_cq); | ||
498 | cqe = ehea_poll_cq(send_cq); | ||
499 | if (!cqe) | ||
500 | break; | ||
501 | } | ||
502 | cqe_counter++; | 496 | cqe_counter++; |
503 | rmb(); | 497 | rmb(); |
504 | if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { | 498 | if (cqe->status & EHEA_CQE_STAT_ERR_MASK) { |
@@ -514,17 +508,25 @@ void ehea_send_irq_tasklet(unsigned long data) | |||
514 | ehea_dump(cqe, sizeof(*cqe), "CQE"); | 508 | ehea_dump(cqe, sizeof(*cqe), "CQE"); |
515 | 509 | ||
516 | if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id) | 510 | if (likely(EHEA_BMASK_GET(EHEA_WR_ID_TYPE, cqe->wr_id) |
517 | == EHEA_SWQE2_TYPE)) | 511 | == EHEA_SWQE2_TYPE)) { |
518 | free_sent_skbs(cqe, pr); | 512 | |
513 | index = EHEA_BMASK_GET(EHEA_WR_ID_INDEX, cqe->wr_id); | ||
514 | skb = pr->sq_skba.arr[index]; | ||
515 | dev_kfree_skb(skb); | ||
516 | pr->sq_skba.arr[index] = NULL; | ||
517 | } | ||
519 | 518 | ||
520 | swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); | 519 | swqe_av += EHEA_BMASK_GET(EHEA_WR_ID_REFILL, cqe->wr_id); |
521 | quota--; | 520 | quota--; |
522 | } while (quota > 0); | 521 | |
522 | cqe = ehea_poll_cq(send_cq); | ||
523 | }; | ||
523 | 524 | ||
524 | ehea_update_feca(send_cq, cqe_counter); | 525 | ehea_update_feca(send_cq, cqe_counter); |
525 | atomic_add(swqe_av, &pr->swqe_avail); | 526 | atomic_add(swqe_av, &pr->swqe_avail); |
526 | 527 | ||
527 | spin_lock_irqsave(&pr->netif_queue, flags); | 528 | spin_lock_irqsave(&pr->netif_queue, flags); |
529 | |||
528 | if (pr->queue_stopped && (atomic_read(&pr->swqe_avail) | 530 | if (pr->queue_stopped && (atomic_read(&pr->swqe_avail) |
529 | >= pr->swqe_refill_th)) { | 531 | >= pr->swqe_refill_th)) { |
530 | netif_wake_queue(pr->port->netdev); | 532 | netif_wake_queue(pr->port->netdev); |
@@ -532,22 +534,55 @@ void ehea_send_irq_tasklet(unsigned long data) | |||
532 | } | 534 | } |
533 | spin_unlock_irqrestore(&pr->netif_queue, flags); | 535 | spin_unlock_irqrestore(&pr->netif_queue, flags); |
534 | 536 | ||
535 | if (unlikely(cqe)) | 537 | return cqe; |
536 | tasklet_hi_schedule(&pr->send_comp_task); | ||
537 | } | 538 | } |
538 | 539 | ||
539 | static irqreturn_t ehea_send_irq_handler(int irq, void *param) | 540 | #define EHEA_NAPI_POLL_NUM_BEFORE_IRQ 16 |
541 | |||
542 | static int ehea_poll(struct net_device *dev, int *budget) | ||
540 | { | 543 | { |
541 | struct ehea_port_res *pr = param; | 544 | struct ehea_port_res *pr = dev->priv; |
542 | tasklet_hi_schedule(&pr->send_comp_task); | 545 | struct ehea_cqe *cqe; |
543 | return IRQ_HANDLED; | 546 | struct ehea_cqe *cqe_skb = NULL; |
547 | int force_irq, wqe_index; | ||
548 | |||
549 | cqe = ehea_poll_rq1(pr->qp, &wqe_index); | ||
550 | cqe_skb = ehea_poll_cq(pr->send_cq); | ||
551 | |||
552 | force_irq = (pr->poll_counter > EHEA_NAPI_POLL_NUM_BEFORE_IRQ); | ||
553 | |||
554 | if ((!cqe && !cqe_skb) || force_irq) { | ||
555 | pr->poll_counter = 0; | ||
556 | netif_rx_complete(dev); | ||
557 | ehea_reset_cq_ep(pr->recv_cq); | ||
558 | ehea_reset_cq_ep(pr->send_cq); | ||
559 | ehea_reset_cq_n1(pr->recv_cq); | ||
560 | ehea_reset_cq_n1(pr->send_cq); | ||
561 | cqe = ehea_poll_rq1(pr->qp, &wqe_index); | ||
562 | cqe_skb = ehea_poll_cq(pr->send_cq); | ||
563 | |||
564 | if (!cqe && !cqe_skb) | ||
565 | return 0; | ||
566 | |||
567 | if (!netif_rx_reschedule(dev, dev->quota)) | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | cqe = ehea_proc_rwqes(dev, pr, budget); | ||
572 | cqe_skb = ehea_proc_cqes(pr, 300); | ||
573 | |||
574 | if (cqe || cqe_skb) | ||
575 | pr->poll_counter++; | ||
576 | |||
577 | return 1; | ||
544 | } | 578 | } |
545 | 579 | ||
546 | static irqreturn_t ehea_recv_irq_handler(int irq, void *param) | 580 | static irqreturn_t ehea_recv_irq_handler(int irq, void *param) |
547 | { | 581 | { |
548 | struct ehea_port_res *pr = param; | 582 | struct ehea_port_res *pr = param; |
549 | struct ehea_port *port = pr->port; | 583 | |
550 | netif_rx_schedule(port->netdev); | 584 | netif_rx_schedule(pr->d_netdev); |
585 | |||
551 | return IRQ_HANDLED; | 586 | return IRQ_HANDLED; |
552 | } | 587 | } |
553 | 588 | ||
@@ -580,7 +615,7 @@ static struct ehea_port *ehea_get_port(struct ehea_adapter *adapter, | |||
580 | { | 615 | { |
581 | int i; | 616 | int i; |
582 | 617 | ||
583 | for (i = 0; i < adapter->num_ports; i++) | 618 | for (i = 0; i < EHEA_MAX_PORTS; i++) |
584 | if (adapter->port[i]) | 619 | if (adapter->port[i]) |
585 | if (adapter->port[i]->logical_port_id == logical_port) | 620 | if (adapter->port[i]->logical_port_id == logical_port) |
586 | return adapter->port[i]; | 621 | return adapter->port[i]; |
@@ -650,19 +685,25 @@ int ehea_sense_port_attr(struct ehea_port *port) | |||
650 | } | 685 | } |
651 | 686 | ||
652 | port->autoneg = 1; | 687 | port->autoneg = 1; |
688 | port->num_mcs = cb0->num_default_qps; | ||
653 | 689 | ||
654 | /* Number of default QPs */ | 690 | /* Number of default QPs */ |
655 | port->num_def_qps = cb0->num_default_qps; | 691 | if (use_mcs) |
692 | port->num_def_qps = cb0->num_default_qps; | ||
693 | else | ||
694 | port->num_def_qps = 1; | ||
656 | 695 | ||
657 | if (!port->num_def_qps) { | 696 | if (!port->num_def_qps) { |
658 | ret = -EINVAL; | 697 | ret = -EINVAL; |
659 | goto out_free; | 698 | goto out_free; |
660 | } | 699 | } |
661 | 700 | ||
662 | if (port->num_def_qps >= EHEA_NUM_TX_QP) | 701 | port->num_tx_qps = num_tx_qps; |
702 | |||
703 | if (port->num_def_qps >= port->num_tx_qps) | ||
663 | port->num_add_tx_qps = 0; | 704 | port->num_add_tx_qps = 0; |
664 | else | 705 | else |
665 | port->num_add_tx_qps = EHEA_NUM_TX_QP - port->num_def_qps; | 706 | port->num_add_tx_qps = port->num_tx_qps - port->num_def_qps; |
666 | 707 | ||
667 | ret = 0; | 708 | ret = 0; |
668 | out_free: | 709 | out_free: |
@@ -882,23 +923,6 @@ static int ehea_reg_interrupts(struct net_device *dev) | |||
882 | struct ehea_port_res *pr; | 923 | struct ehea_port_res *pr; |
883 | int i, ret; | 924 | int i, ret; |
884 | 925 | ||
885 | for (i = 0; i < port->num_def_qps; i++) { | ||
886 | pr = &port->port_res[i]; | ||
887 | snprintf(pr->int_recv_name, EHEA_IRQ_NAME_SIZE - 1 | ||
888 | , "%s-recv%d", dev->name, i); | ||
889 | ret = ibmebus_request_irq(NULL, pr->recv_eq->attr.ist1, | ||
890 | ehea_recv_irq_handler, | ||
891 | IRQF_DISABLED, pr->int_recv_name, pr); | ||
892 | if (ret) { | ||
893 | ehea_error("failed registering irq for ehea_recv_int:" | ||
894 | "port_res_nr:%d, ist=%X", i, | ||
895 | pr->recv_eq->attr.ist1); | ||
896 | goto out_free_seq; | ||
897 | } | ||
898 | if (netif_msg_ifup(port)) | ||
899 | ehea_info("irq_handle 0x%X for funct ehea_recv_int %d " | ||
900 | "registered", pr->recv_eq->attr.ist1, i); | ||
901 | } | ||
902 | 926 | ||
903 | snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff", | 927 | snprintf(port->int_aff_name, EHEA_IRQ_NAME_SIZE - 1, "%s-aff", |
904 | dev->name); | 928 | dev->name); |
@@ -916,41 +940,41 @@ static int ehea_reg_interrupts(struct net_device *dev) | |||
916 | ehea_info("irq_handle 0x%X for function qp_aff_irq_handler " | 940 | ehea_info("irq_handle 0x%X for function qp_aff_irq_handler " |
917 | "registered", port->qp_eq->attr.ist1); | 941 | "registered", port->qp_eq->attr.ist1); |
918 | 942 | ||
943 | |||
919 | for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { | 944 | for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { |
920 | pr = &port->port_res[i]; | 945 | pr = &port->port_res[i]; |
921 | snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1, | 946 | snprintf(pr->int_send_name, EHEA_IRQ_NAME_SIZE - 1, |
922 | "%s-send%d", dev->name, i); | 947 | "%s-queue%d", dev->name, i); |
923 | ret = ibmebus_request_irq(NULL, pr->send_eq->attr.ist1, | 948 | ret = ibmebus_request_irq(NULL, pr->eq->attr.ist1, |
924 | ehea_send_irq_handler, | 949 | ehea_recv_irq_handler, |
925 | IRQF_DISABLED, pr->int_send_name, | 950 | IRQF_DISABLED, pr->int_send_name, |
926 | pr); | 951 | pr); |
927 | if (ret) { | 952 | if (ret) { |
928 | ehea_error("failed registering irq for ehea_send " | 953 | ehea_error("failed registering irq for ehea_queue " |
929 | "port_res_nr:%d, ist=%X", i, | 954 | "port_res_nr:%d, ist=%X", i, |
930 | pr->send_eq->attr.ist1); | 955 | pr->eq->attr.ist1); |
931 | goto out_free_req; | 956 | goto out_free_req; |
932 | } | 957 | } |
933 | if (netif_msg_ifup(port)) | 958 | if (netif_msg_ifup(port)) |
934 | ehea_info("irq_handle 0x%X for function ehea_send_int " | 959 | ehea_info("irq_handle 0x%X for function ehea_queue_int " |
935 | "%d registered", pr->send_eq->attr.ist1, i); | 960 | "%d registered", pr->eq->attr.ist1, i); |
936 | } | 961 | } |
937 | out: | 962 | out: |
938 | return ret; | 963 | return ret; |
939 | 964 | ||
965 | |||
940 | out_free_req: | 966 | out_free_req: |
941 | while (--i >= 0) { | 967 | while (--i >= 0) { |
942 | u32 ist = port->port_res[i].send_eq->attr.ist1; | 968 | u32 ist = port->port_res[i].eq->attr.ist1; |
943 | ibmebus_free_irq(NULL, ist, &port->port_res[i]); | 969 | ibmebus_free_irq(NULL, ist, &port->port_res[i]); |
944 | } | 970 | } |
971 | |||
945 | out_free_qpeq: | 972 | out_free_qpeq: |
946 | ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port); | 973 | ibmebus_free_irq(NULL, port->qp_eq->attr.ist1, port); |
947 | i = port->num_def_qps; | 974 | i = port->num_def_qps; |
948 | out_free_seq: | 975 | |
949 | while (--i >= 0) { | ||
950 | u32 ist = port->port_res[i].recv_eq->attr.ist1; | ||
951 | ibmebus_free_irq(NULL, ist, &port->port_res[i]); | ||
952 | } | ||
953 | goto out; | 976 | goto out; |
977 | |||
954 | } | 978 | } |
955 | 979 | ||
956 | static void ehea_free_interrupts(struct net_device *dev) | 980 | static void ehea_free_interrupts(struct net_device *dev) |
@@ -960,21 +984,13 @@ static void ehea_free_interrupts(struct net_device *dev) | |||
960 | int i; | 984 | int i; |
961 | 985 | ||
962 | /* send */ | 986 | /* send */ |
987 | |||
963 | for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { | 988 | for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) { |
964 | pr = &port->port_res[i]; | 989 | pr = &port->port_res[i]; |
965 | ibmebus_free_irq(NULL, pr->send_eq->attr.ist1, pr); | 990 | ibmebus_free_irq(NULL, pr->eq->attr.ist1, pr); |
966 | if (netif_msg_intr(port)) | 991 | if (netif_msg_intr(port)) |
967 | ehea_info("free send irq for res %d with handle 0x%X", | 992 | ehea_info("free send irq for res %d with handle 0x%X", |
968 | i, pr->send_eq->attr.ist1); | 993 | i, pr->eq->attr.ist1); |
969 | } | ||
970 | |||
971 | /* receive */ | ||
972 | for (i = 0; i < port->num_def_qps; i++) { | ||
973 | pr = &port->port_res[i]; | ||
974 | ibmebus_free_irq(NULL, pr->recv_eq->attr.ist1, pr); | ||
975 | if (netif_msg_intr(port)) | ||
976 | ehea_info("free recv irq for res %d with handle 0x%X", | ||
977 | i, pr->recv_eq->attr.ist1); | ||
978 | } | 994 | } |
979 | 995 | ||
980 | /* associated events */ | 996 | /* associated events */ |
@@ -1003,8 +1019,13 @@ static int ehea_configure_port(struct ehea_port *port) | |||
1003 | PXLY_RC_VLAN_FILTER) | 1019 | PXLY_RC_VLAN_FILTER) |
1004 | | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1); | 1020 | | EHEA_BMASK_SET(PXLY_RC_JUMBO_FRAME, 1); |
1005 | 1021 | ||
1006 | for (i = 0; i < port->num_def_qps; i++) | 1022 | for (i = 0; i < port->num_mcs; i++) |
1007 | cb0->default_qpn_arr[i] = port->port_res[0].qp->init_attr.qp_nr; | 1023 | if (use_mcs) |
1024 | cb0->default_qpn_arr[i] = | ||
1025 | port->port_res[i].qp->init_attr.qp_nr; | ||
1026 | else | ||
1027 | cb0->default_qpn_arr[i] = | ||
1028 | port->port_res[0].qp->init_attr.qp_nr; | ||
1008 | 1029 | ||
1009 | if (netif_msg_ifup(port)) | 1030 | if (netif_msg_ifup(port)) |
1010 | ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port"); | 1031 | ehea_dump(cb0, sizeof(*cb0), "ehea_configure_port"); |
@@ -1027,52 +1048,35 @@ out: | |||
1027 | return ret; | 1048 | return ret; |
1028 | } | 1049 | } |
1029 | 1050 | ||
1030 | static int ehea_gen_smrs(struct ehea_port_res *pr) | 1051 | int ehea_gen_smrs(struct ehea_port_res *pr) |
1031 | { | 1052 | { |
1032 | u64 hret; | 1053 | int ret; |
1033 | struct ehea_adapter *adapter = pr->port->adapter; | 1054 | struct ehea_adapter *adapter = pr->port->adapter; |
1034 | 1055 | ||
1035 | hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle, | 1056 | ret = ehea_gen_smr(adapter, &adapter->mr, &pr->send_mr); |
1036 | adapter->mr.vaddr, EHEA_MR_ACC_CTRL, | 1057 | if (ret) |
1037 | adapter->pd, &pr->send_mr); | ||
1038 | if (hret != H_SUCCESS) | ||
1039 | goto out; | 1058 | goto out; |
1040 | 1059 | ||
1041 | hret = ehea_h_register_smr(adapter->handle, adapter->mr.handle, | 1060 | ret = ehea_gen_smr(adapter, &adapter->mr, &pr->recv_mr); |
1042 | adapter->mr.vaddr, EHEA_MR_ACC_CTRL, | 1061 | if (ret) |
1043 | adapter->pd, &pr->recv_mr); | 1062 | goto out_free; |
1044 | if (hret != H_SUCCESS) | ||
1045 | goto out_freeres; | ||
1046 | 1063 | ||
1047 | return 0; | 1064 | return 0; |
1048 | 1065 | ||
1049 | out_freeres: | 1066 | out_free: |
1050 | hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle); | 1067 | ehea_rem_mr(&pr->send_mr); |
1051 | if (hret != H_SUCCESS) | ||
1052 | ehea_error("failed freeing SMR"); | ||
1053 | out: | 1068 | out: |
1069 | ehea_error("Generating SMRS failed\n"); | ||
1054 | return -EIO; | 1070 | return -EIO; |
1055 | } | 1071 | } |
1056 | 1072 | ||
1057 | static int ehea_rem_smrs(struct ehea_port_res *pr) | 1073 | int ehea_rem_smrs(struct ehea_port_res *pr) |
1058 | { | 1074 | { |
1059 | struct ehea_adapter *adapter = pr->port->adapter; | 1075 | if ((ehea_rem_mr(&pr->send_mr)) |
1060 | int ret = 0; | 1076 | || (ehea_rem_mr(&pr->recv_mr))) |
1061 | u64 hret; | 1077 | return -EIO; |
1062 | 1078 | else | |
1063 | hret = ehea_h_free_resource(adapter->handle, pr->send_mr.handle); | 1079 | return 0; |
1064 | if (hret != H_SUCCESS) { | ||
1065 | ret = -EIO; | ||
1066 | ehea_error("failed freeing send SMR for pr=%p", pr); | ||
1067 | } | ||
1068 | |||
1069 | hret = ehea_h_free_resource(adapter->handle, pr->recv_mr.handle); | ||
1070 | if (hret != H_SUCCESS) { | ||
1071 | ret = -EIO; | ||
1072 | ehea_error("failed freeing recv SMR for pr=%p", pr); | ||
1073 | } | ||
1074 | |||
1075 | return ret; | ||
1076 | } | 1080 | } |
1077 | 1081 | ||
1078 | static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries) | 1082 | static int ehea_init_q_skba(struct ehea_q_skb_arr *q_skba, int max_q_entries) |
@@ -1103,25 +1107,17 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, | |||
1103 | memset(pr, 0, sizeof(struct ehea_port_res)); | 1107 | memset(pr, 0, sizeof(struct ehea_port_res)); |
1104 | 1108 | ||
1105 | pr->port = port; | 1109 | pr->port = port; |
1106 | spin_lock_init(&pr->send_lock); | ||
1107 | spin_lock_init(&pr->recv_lock); | ||
1108 | spin_lock_init(&pr->xmit_lock); | 1110 | spin_lock_init(&pr->xmit_lock); |
1109 | spin_lock_init(&pr->netif_queue); | 1111 | spin_lock_init(&pr->netif_queue); |
1110 | 1112 | ||
1111 | pr->recv_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); | 1113 | pr->eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); |
1112 | if (!pr->recv_eq) { | 1114 | if (!pr->eq) { |
1113 | ehea_error("create_eq failed (recv_eq)"); | 1115 | ehea_error("create_eq failed (eq)"); |
1114 | goto out_free; | ||
1115 | } | ||
1116 | |||
1117 | pr->send_eq = ehea_create_eq(adapter, eq_type, EHEA_MAX_ENTRIES_EQ, 0); | ||
1118 | if (!pr->send_eq) { | ||
1119 | ehea_error("create_eq failed (send_eq)"); | ||
1120 | goto out_free; | 1116 | goto out_free; |
1121 | } | 1117 | } |
1122 | 1118 | ||
1123 | pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq, | 1119 | pr->recv_cq = ehea_create_cq(adapter, pr_cfg->max_entries_rcq, |
1124 | pr->recv_eq->fw_handle, | 1120 | pr->eq->fw_handle, |
1125 | port->logical_port_id); | 1121 | port->logical_port_id); |
1126 | if (!pr->recv_cq) { | 1122 | if (!pr->recv_cq) { |
1127 | ehea_error("create_cq failed (cq_recv)"); | 1123 | ehea_error("create_cq failed (cq_recv)"); |
@@ -1129,7 +1125,7 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, | |||
1129 | } | 1125 | } |
1130 | 1126 | ||
1131 | pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq, | 1127 | pr->send_cq = ehea_create_cq(adapter, pr_cfg->max_entries_scq, |
1132 | pr->send_eq->fw_handle, | 1128 | pr->eq->fw_handle, |
1133 | port->logical_port_id); | 1129 | port->logical_port_id); |
1134 | if (!pr->send_cq) { | 1130 | if (!pr->send_cq) { |
1135 | ehea_error("create_cq failed (cq_send)"); | 1131 | ehea_error("create_cq failed (cq_send)"); |
@@ -1194,11 +1190,20 @@ static int ehea_init_port_res(struct ehea_port *port, struct ehea_port_res *pr, | |||
1194 | ret = -EIO; | 1190 | ret = -EIO; |
1195 | goto out_free; | 1191 | goto out_free; |
1196 | } | 1192 | } |
1197 | tasklet_init(&pr->send_comp_task, ehea_send_irq_tasklet, | 1193 | |
1198 | (unsigned long)pr); | ||
1199 | atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1); | 1194 | atomic_set(&pr->swqe_avail, init_attr->act_nr_send_wqes - 1); |
1200 | 1195 | ||
1201 | kfree(init_attr); | 1196 | kfree(init_attr); |
1197 | |||
1198 | pr->d_netdev = alloc_netdev(0, "", ether_setup); | ||
1199 | if (!pr->d_netdev) | ||
1200 | goto out_free; | ||
1201 | pr->d_netdev->priv = pr; | ||
1202 | pr->d_netdev->weight = 64; | ||
1203 | pr->d_netdev->poll = ehea_poll; | ||
1204 | set_bit(__LINK_STATE_START, &pr->d_netdev->state); | ||
1205 | strcpy(pr->d_netdev->name, port->netdev->name); | ||
1206 | |||
1202 | ret = 0; | 1207 | ret = 0; |
1203 | goto out; | 1208 | goto out; |
1204 | 1209 | ||
@@ -1211,8 +1216,7 @@ out_free: | |||
1211 | ehea_destroy_qp(pr->qp); | 1216 | ehea_destroy_qp(pr->qp); |
1212 | ehea_destroy_cq(pr->send_cq); | 1217 | ehea_destroy_cq(pr->send_cq); |
1213 | ehea_destroy_cq(pr->recv_cq); | 1218 | ehea_destroy_cq(pr->recv_cq); |
1214 | ehea_destroy_eq(pr->send_eq); | 1219 | ehea_destroy_eq(pr->eq); |
1215 | ehea_destroy_eq(pr->recv_eq); | ||
1216 | out: | 1220 | out: |
1217 | return ret; | 1221 | return ret; |
1218 | } | 1222 | } |
@@ -1221,13 +1225,14 @@ static int ehea_clean_portres(struct ehea_port *port, struct ehea_port_res *pr) | |||
1221 | { | 1225 | { |
1222 | int ret, i; | 1226 | int ret, i; |
1223 | 1227 | ||
1228 | free_netdev(pr->d_netdev); | ||
1229 | |||
1224 | ret = ehea_destroy_qp(pr->qp); | 1230 | ret = ehea_destroy_qp(pr->qp); |
1225 | 1231 | ||
1226 | if (!ret) { | 1232 | if (!ret) { |
1227 | ehea_destroy_cq(pr->send_cq); | 1233 | ehea_destroy_cq(pr->send_cq); |
1228 | ehea_destroy_cq(pr->recv_cq); | 1234 | ehea_destroy_cq(pr->recv_cq); |
1229 | ehea_destroy_eq(pr->send_eq); | 1235 | ehea_destroy_eq(pr->eq); |
1230 | ehea_destroy_eq(pr->recv_eq); | ||
1231 | 1236 | ||
1232 | for (i = 0; i < pr->rq1_skba.len; i++) | 1237 | for (i = 0; i < pr->rq1_skba.len; i++) |
1233 | if (pr->rq1_skba.arr[i]) | 1238 | if (pr->rq1_skba.arr[i]) |
@@ -1792,6 +1797,22 @@ static void ehea_xmit3(struct sk_buff *skb, struct net_device *dev, | |||
1792 | dev_kfree_skb(skb); | 1797 | dev_kfree_skb(skb); |
1793 | } | 1798 | } |
1794 | 1799 | ||
1800 | static inline int ehea_hash_skb(struct sk_buff *skb, int num_qps) | ||
1801 | { | ||
1802 | struct tcphdr *tcp; | ||
1803 | u32 tmp; | ||
1804 | |||
1805 | if ((skb->protocol == htons(ETH_P_IP)) && | ||
1806 | (skb->nh.iph->protocol == IPPROTO_TCP)) { | ||
1807 | tcp = (struct tcphdr*)(skb->nh.raw + (skb->nh.iph->ihl * 4)); | ||
1808 | tmp = (tcp->source + (tcp->dest << 16)) % 31; | ||
1809 | tmp += skb->nh.iph->daddr % 31; | ||
1810 | return tmp % num_qps; | ||
1811 | } | ||
1812 | else | ||
1813 | return 0; | ||
1814 | } | ||
1815 | |||
1795 | static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) | 1816 | static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) |
1796 | { | 1817 | { |
1797 | struct ehea_port *port = netdev_priv(dev); | 1818 | struct ehea_port *port = netdev_priv(dev); |
@@ -1799,9 +1820,17 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1799 | unsigned long flags; | 1820 | unsigned long flags; |
1800 | u32 lkey; | 1821 | u32 lkey; |
1801 | int swqe_index; | 1822 | int swqe_index; |
1802 | struct ehea_port_res *pr = &port->port_res[0]; | 1823 | struct ehea_port_res *pr; |
1824 | |||
1825 | pr = &port->port_res[ehea_hash_skb(skb, port->num_tx_qps)]; | ||
1803 | 1826 | ||
1804 | spin_lock(&pr->xmit_lock); | 1827 | if (!spin_trylock(&pr->xmit_lock)) |
1828 | return NETDEV_TX_BUSY; | ||
1829 | |||
1830 | if (pr->queue_stopped) { | ||
1831 | spin_unlock(&pr->xmit_lock); | ||
1832 | return NETDEV_TX_BUSY; | ||
1833 | } | ||
1805 | 1834 | ||
1806 | swqe = ehea_get_swqe(pr->qp, &swqe_index); | 1835 | swqe = ehea_get_swqe(pr->qp, &swqe_index); |
1807 | memset(swqe, 0, SWQE_HEADER_SIZE); | 1836 | memset(swqe, 0, SWQE_HEADER_SIZE); |
@@ -1824,6 +1853,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1824 | swqe->wr_id = | 1853 | swqe->wr_id = |
1825 | EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE) | 1854 | EHEA_BMASK_SET(EHEA_WR_ID_TYPE, EHEA_SWQE2_TYPE) |
1826 | | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter) | 1855 | | EHEA_BMASK_SET(EHEA_WR_ID_COUNT, pr->swqe_id_counter) |
1856 | | EHEA_BMASK_SET(EHEA_WR_ID_REFILL, 1) | ||
1827 | | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index); | 1857 | | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, pr->sq_skba.index); |
1828 | pr->sq_skba.arr[pr->sq_skba.index] = skb; | 1858 | pr->sq_skba.arr[pr->sq_skba.index] = skb; |
1829 | 1859 | ||
@@ -1832,14 +1862,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1832 | 1862 | ||
1833 | lkey = pr->send_mr.lkey; | 1863 | lkey = pr->send_mr.lkey; |
1834 | ehea_xmit2(skb, dev, swqe, lkey); | 1864 | ehea_xmit2(skb, dev, swqe, lkey); |
1835 | 1865 | swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; | |
1836 | if (pr->swqe_count >= (EHEA_SIG_IV_LONG - 1)) { | ||
1837 | swqe->wr_id |= EHEA_BMASK_SET(EHEA_WR_ID_REFILL, | ||
1838 | EHEA_SIG_IV_LONG); | ||
1839 | swqe->tx_control |= EHEA_SWQE_SIGNALLED_COMPLETION; | ||
1840 | pr->swqe_count = 0; | ||
1841 | } else | ||
1842 | pr->swqe_count += 1; | ||
1843 | } | 1866 | } |
1844 | pr->swqe_id_counter += 1; | 1867 | pr->swqe_id_counter += 1; |
1845 | 1868 | ||
@@ -1859,6 +1882,7 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
1859 | if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { | 1882 | if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { |
1860 | spin_lock_irqsave(&pr->netif_queue, flags); | 1883 | spin_lock_irqsave(&pr->netif_queue, flags); |
1861 | if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { | 1884 | if (unlikely(atomic_read(&pr->swqe_avail) <= 1)) { |
1885 | pr->p_stats.queue_stopped++; | ||
1862 | netif_stop_queue(dev); | 1886 | netif_stop_queue(dev); |
1863 | pr->queue_stopped = 1; | 1887 | pr->queue_stopped = 1; |
1864 | } | 1888 | } |
@@ -2060,7 +2084,7 @@ static int ehea_port_res_setup(struct ehea_port *port, int def_qps, | |||
2060 | } | 2084 | } |
2061 | 2085 | ||
2062 | pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries; | 2086 | pr_cfg.max_entries_rcq = rq1_entries + rq2_entries + rq3_entries; |
2063 | pr_cfg.max_entries_scq = sq_entries; | 2087 | pr_cfg.max_entries_scq = sq_entries * 2; |
2064 | pr_cfg.max_entries_sq = sq_entries; | 2088 | pr_cfg.max_entries_sq = sq_entries; |
2065 | pr_cfg.max_entries_rq1 = rq1_entries; | 2089 | pr_cfg.max_entries_rq1 = rq1_entries; |
2066 | pr_cfg.max_entries_rq2 = rq2_entries; | 2090 | pr_cfg.max_entries_rq2 = rq2_entries; |
@@ -2109,6 +2133,28 @@ static int ehea_clean_all_portres(struct ehea_port *port) | |||
2109 | return ret; | 2133 | return ret; |
2110 | } | 2134 | } |
2111 | 2135 | ||
2136 | static void ehea_remove_adapter_mr (struct ehea_adapter *adapter) | ||
2137 | { | ||
2138 | int i; | ||
2139 | |||
2140 | for (i=0; i < EHEA_MAX_PORTS; i++) | ||
2141 | if (adapter->port[i]) | ||
2142 | return; | ||
2143 | |||
2144 | ehea_rem_mr(&adapter->mr); | ||
2145 | } | ||
2146 | |||
2147 | static int ehea_add_adapter_mr (struct ehea_adapter *adapter) | ||
2148 | { | ||
2149 | int i; | ||
2150 | |||
2151 | for (i=0; i < EHEA_MAX_PORTS; i++) | ||
2152 | if (adapter->port[i]) | ||
2153 | return 0; | ||
2154 | |||
2155 | return ehea_reg_kernel_mr(adapter, &adapter->mr); | ||
2156 | } | ||
2157 | |||
2112 | static int ehea_up(struct net_device *dev) | 2158 | static int ehea_up(struct net_device *dev) |
2113 | { | 2159 | { |
2114 | int ret, i; | 2160 | int ret, i; |
@@ -2208,8 +2254,10 @@ static int ehea_down(struct net_device *dev) | |||
2208 | ehea_drop_multicast_list(dev); | 2254 | ehea_drop_multicast_list(dev); |
2209 | ehea_free_interrupts(dev); | 2255 | ehea_free_interrupts(dev); |
2210 | 2256 | ||
2211 | for (i = 0; i < port->num_def_qps + port->num_add_tx_qps; i++) | 2257 | for (i = 0; i < port->num_def_qps; i++) |
2212 | tasklet_kill(&port->port_res[i].send_comp_task); | 2258 | while (test_bit(__LINK_STATE_RX_SCHED, |
2259 | &port->port_res[i].d_netdev->state)) | ||
2260 | msleep(1); | ||
2213 | 2261 | ||
2214 | ehea_broadcast_reg_helper(port, H_DEREG_BCMC); | 2262 | ehea_broadcast_reg_helper(port, H_DEREG_BCMC); |
2215 | ret = ehea_clean_all_portres(port); | 2263 | ret = ehea_clean_all_portres(port); |
@@ -2276,8 +2324,6 @@ static void ehea_tx_watchdog(struct net_device *dev) | |||
2276 | int ehea_sense_adapter_attr(struct ehea_adapter *adapter) | 2324 | int ehea_sense_adapter_attr(struct ehea_adapter *adapter) |
2277 | { | 2325 | { |
2278 | struct hcp_query_ehea *cb; | 2326 | struct hcp_query_ehea *cb; |
2279 | struct device_node *lhea_dn = NULL; | ||
2280 | struct device_node *eth_dn = NULL; | ||
2281 | u64 hret; | 2327 | u64 hret; |
2282 | int ret; | 2328 | int ret; |
2283 | 2329 | ||
@@ -2294,18 +2340,6 @@ int ehea_sense_adapter_attr(struct ehea_adapter *adapter) | |||
2294 | goto out_herr; | 2340 | goto out_herr; |
2295 | } | 2341 | } |
2296 | 2342 | ||
2297 | /* Determine the number of available logical ports | ||
2298 | * by counting the child nodes of the lhea OFDT entry | ||
2299 | */ | ||
2300 | adapter->num_ports = 0; | ||
2301 | lhea_dn = of_find_node_by_name(lhea_dn, "lhea"); | ||
2302 | do { | ||
2303 | eth_dn = of_get_next_child(lhea_dn, eth_dn); | ||
2304 | if (eth_dn) | ||
2305 | adapter->num_ports++; | ||
2306 | } while ( eth_dn ); | ||
2307 | of_node_put(lhea_dn); | ||
2308 | |||
2309 | adapter->max_mc_mac = cb->max_mc_mac - 1; | 2343 | adapter->max_mc_mac = cb->max_mc_mac - 1; |
2310 | ret = 0; | 2344 | ret = 0; |
2311 | 2345 | ||
@@ -2315,79 +2349,188 @@ out: | |||
2315 | return ret; | 2349 | return ret; |
2316 | } | 2350 | } |
2317 | 2351 | ||
2318 | static int ehea_setup_single_port(struct ehea_port *port, | 2352 | int ehea_get_jumboframe_status(struct ehea_port *port, int *jumbo) |
2319 | struct device_node *dn) | ||
2320 | { | 2353 | { |
2321 | int ret; | ||
2322 | u64 hret; | ||
2323 | struct net_device *dev = port->netdev; | ||
2324 | struct ehea_adapter *adapter = port->adapter; | ||
2325 | struct hcp_ehea_port_cb4 *cb4; | 2354 | struct hcp_ehea_port_cb4 *cb4; |
2326 | u32 *dn_log_port_id; | 2355 | u64 hret; |
2327 | int jumbo = 0; | 2356 | int ret = 0; |
2328 | |||
2329 | sema_init(&port->port_lock, 1); | ||
2330 | port->state = EHEA_PORT_DOWN; | ||
2331 | port->sig_comp_iv = sq_entries / 10; | ||
2332 | |||
2333 | if (!dn) { | ||
2334 | ehea_error("bad device node: dn=%p", dn); | ||
2335 | ret = -EINVAL; | ||
2336 | goto out; | ||
2337 | } | ||
2338 | |||
2339 | port->of_dev_node = dn; | ||
2340 | |||
2341 | /* Determine logical port id */ | ||
2342 | dn_log_port_id = (u32*)get_property(dn, "ibm,hea-port-no", NULL); | ||
2343 | |||
2344 | if (!dn_log_port_id) { | ||
2345 | ehea_error("bad device node: dn_log_port_id=%p", | ||
2346 | dn_log_port_id); | ||
2347 | ret = -EINVAL; | ||
2348 | goto out; | ||
2349 | } | ||
2350 | port->logical_port_id = *dn_log_port_id; | ||
2351 | |||
2352 | port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); | ||
2353 | if (!port->mc_list) { | ||
2354 | ret = -ENOMEM; | ||
2355 | goto out; | ||
2356 | } | ||
2357 | |||
2358 | INIT_LIST_HEAD(&port->mc_list->list); | ||
2359 | 2357 | ||
2360 | ret = ehea_sense_port_attr(port); | 2358 | *jumbo = 0; |
2361 | if (ret) | ||
2362 | goto out; | ||
2363 | 2359 | ||
2364 | /* Enable Jumbo frames */ | 2360 | /* (Try to) enable *jumbo frames */ |
2365 | cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); | 2361 | cb4 = kzalloc(PAGE_SIZE, GFP_KERNEL); |
2366 | if (!cb4) { | 2362 | if (!cb4) { |
2367 | ehea_error("no mem for cb4"); | 2363 | ehea_error("no mem for cb4"); |
2364 | ret = -ENOMEM; | ||
2365 | goto out; | ||
2368 | } else { | 2366 | } else { |
2369 | hret = ehea_h_query_ehea_port(adapter->handle, | 2367 | hret = ehea_h_query_ehea_port(port->adapter->handle, |
2370 | port->logical_port_id, | 2368 | port->logical_port_id, |
2371 | H_PORT_CB4, | 2369 | H_PORT_CB4, |
2372 | H_PORT_CB4_JUMBO, cb4); | 2370 | H_PORT_CB4_JUMBO, cb4); |
2373 | |||
2374 | if (hret == H_SUCCESS) { | 2371 | if (hret == H_SUCCESS) { |
2375 | if (cb4->jumbo_frame) | 2372 | if (cb4->jumbo_frame) |
2376 | jumbo = 1; | 2373 | *jumbo = 1; |
2377 | else { | 2374 | else { |
2378 | cb4->jumbo_frame = 1; | 2375 | cb4->jumbo_frame = 1; |
2379 | hret = ehea_h_modify_ehea_port(adapter->handle, | 2376 | hret = ehea_h_modify_ehea_port(port->adapter-> |
2377 | handle, | ||
2380 | port-> | 2378 | port-> |
2381 | logical_port_id, | 2379 | logical_port_id, |
2382 | H_PORT_CB4, | 2380 | H_PORT_CB4, |
2383 | H_PORT_CB4_JUMBO, | 2381 | H_PORT_CB4_JUMBO, |
2384 | cb4); | 2382 | cb4); |
2385 | if (hret == H_SUCCESS) | 2383 | if (hret == H_SUCCESS) |
2386 | jumbo = 1; | 2384 | *jumbo = 1; |
2387 | } | 2385 | } |
2388 | } | 2386 | } else |
2387 | ret = -EINVAL; | ||
2388 | |||
2389 | kfree(cb4); | 2389 | kfree(cb4); |
2390 | } | 2390 | } |
2391 | out: | ||
2392 | return ret; | ||
2393 | } | ||
2394 | |||
2395 | static ssize_t ehea_show_port_id(struct device *dev, | ||
2396 | struct device_attribute *attr, char *buf) | ||
2397 | { | ||
2398 | struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); | ||
2399 | return sprintf(buf, "0x%X", port->logical_port_id); | ||
2400 | } | ||
2401 | |||
2402 | static DEVICE_ATTR(log_port_id, S_IRUSR | S_IRGRP | S_IROTH, ehea_show_port_id, | ||
2403 | NULL); | ||
2404 | |||
2405 | static void __devinit logical_port_release(struct device *dev) | ||
2406 | { | ||
2407 | struct ehea_port *port = container_of(dev, struct ehea_port, ofdev.dev); | ||
2408 | of_node_put(port->ofdev.node); | ||
2409 | } | ||
2410 | |||
2411 | static int ehea_driver_sysfs_add(struct device *dev, | ||
2412 | struct device_driver *driver) | ||
2413 | { | ||
2414 | int ret; | ||
2415 | |||
2416 | ret = sysfs_create_link(&driver->kobj, &dev->kobj, | ||
2417 | kobject_name(&dev->kobj)); | ||
2418 | if (ret == 0) { | ||
2419 | ret = sysfs_create_link(&dev->kobj, &driver->kobj, | ||
2420 | "driver"); | ||
2421 | if (ret) | ||
2422 | sysfs_remove_link(&driver->kobj, | ||
2423 | kobject_name(&dev->kobj)); | ||
2424 | } | ||
2425 | return ret; | ||
2426 | } | ||
2427 | |||
2428 | static void ehea_driver_sysfs_remove(struct device *dev, | ||
2429 | struct device_driver *driver) | ||
2430 | { | ||
2431 | struct device_driver *drv = driver; | ||
2432 | |||
2433 | if (drv) { | ||
2434 | sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); | ||
2435 | sysfs_remove_link(&dev->kobj, "driver"); | ||
2436 | } | ||
2437 | } | ||
2438 | |||
2439 | static struct device *ehea_register_port(struct ehea_port *port, | ||
2440 | struct device_node *dn) | ||
2441 | { | ||
2442 | int ret; | ||
2443 | |||
2444 | port->ofdev.node = of_node_get(dn); | ||
2445 | port->ofdev.dev.parent = &port->adapter->ebus_dev->ofdev.dev; | ||
2446 | port->ofdev.dev.bus = &ibmebus_bus_type; | ||
2447 | |||
2448 | sprintf(port->ofdev.dev.bus_id, "port%d", port_name_cnt++); | ||
2449 | port->ofdev.dev.release = logical_port_release; | ||
2450 | |||
2451 | ret = of_device_register(&port->ofdev); | ||
2452 | if (ret) { | ||
2453 | ehea_error("failed to register device. ret=%d", ret); | ||
2454 | goto out; | ||
2455 | } | ||
2456 | |||
2457 | ret = device_create_file(&port->ofdev.dev, &dev_attr_log_port_id); | ||
2458 | if (ret) { | ||
2459 | ehea_error("failed to register attributes, ret=%d", ret); | ||
2460 | goto out_unreg_of_dev; | ||
2461 | } | ||
2462 | |||
2463 | ret = ehea_driver_sysfs_add(&port->ofdev.dev, &ehea_driver.driver); | ||
2464 | if (ret) { | ||
2465 | ehea_error("failed to register sysfs driver link"); | ||
2466 | goto out_rem_dev_file; | ||
2467 | } | ||
2468 | |||
2469 | return &port->ofdev.dev; | ||
2470 | |||
2471 | out_rem_dev_file: | ||
2472 | device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); | ||
2473 | out_unreg_of_dev: | ||
2474 | of_device_unregister(&port->ofdev); | ||
2475 | out: | ||
2476 | return NULL; | ||
2477 | } | ||
2478 | |||
2479 | static void ehea_unregister_port(struct ehea_port *port) | ||
2480 | { | ||
2481 | ehea_driver_sysfs_remove(&port->ofdev.dev, &ehea_driver.driver); | ||
2482 | device_remove_file(&port->ofdev.dev, &dev_attr_log_port_id); | ||
2483 | of_device_unregister(&port->ofdev); | ||
2484 | } | ||
2485 | |||
2486 | struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter, | ||
2487 | u32 logical_port_id, | ||
2488 | struct device_node *dn) | ||
2489 | { | ||
2490 | int ret; | ||
2491 | struct net_device *dev; | ||
2492 | struct ehea_port *port; | ||
2493 | struct device *port_dev; | ||
2494 | int jumbo; | ||
2495 | |||
2496 | /* allocate memory for the port structures */ | ||
2497 | dev = alloc_etherdev(sizeof(struct ehea_port)); | ||
2498 | |||
2499 | if (!dev) { | ||
2500 | ehea_error("no mem for net_device"); | ||
2501 | ret = -ENOMEM; | ||
2502 | goto out_err; | ||
2503 | } | ||
2504 | |||
2505 | port = netdev_priv(dev); | ||
2506 | |||
2507 | sema_init(&port->port_lock, 1); | ||
2508 | port->state = EHEA_PORT_DOWN; | ||
2509 | port->sig_comp_iv = sq_entries / 10; | ||
2510 | |||
2511 | port->adapter = adapter; | ||
2512 | port->netdev = dev; | ||
2513 | port->logical_port_id = logical_port_id; | ||
2514 | |||
2515 | port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); | ||
2516 | |||
2517 | port->mc_list = kzalloc(sizeof(struct ehea_mc_list), GFP_KERNEL); | ||
2518 | if (!port->mc_list) { | ||
2519 | ret = -ENOMEM; | ||
2520 | goto out_free_ethdev; | ||
2521 | } | ||
2522 | |||
2523 | INIT_LIST_HEAD(&port->mc_list->list); | ||
2524 | |||
2525 | ret = ehea_sense_port_attr(port); | ||
2526 | if (ret) | ||
2527 | goto out_free_mc_list; | ||
2528 | |||
2529 | port_dev = ehea_register_port(port, dn); | ||
2530 | if (!port_dev) | ||
2531 | goto out_free_mc_list; | ||
2532 | |||
2533 | SET_NETDEV_DEV(dev, port_dev); | ||
2391 | 2534 | ||
2392 | /* initialize net_device structure */ | 2535 | /* initialize net_device structure */ |
2393 | SET_MODULE_OWNER(dev); | 2536 | SET_MODULE_OWNER(dev); |
@@ -2420,84 +2563,225 @@ static int ehea_setup_single_port(struct ehea_port *port, | |||
2420 | ret = register_netdev(dev); | 2563 | ret = register_netdev(dev); |
2421 | if (ret) { | 2564 | if (ret) { |
2422 | ehea_error("register_netdev failed. ret=%d", ret); | 2565 | ehea_error("register_netdev failed. ret=%d", ret); |
2423 | goto out_free; | 2566 | goto out_unreg_port; |
2424 | } | 2567 | } |
2425 | 2568 | ||
2569 | ret = ehea_get_jumboframe_status(port, &jumbo); | ||
2570 | if (ret) | ||
2571 | ehea_error("failed determining jumbo frame status for %s", | ||
2572 | port->netdev->name); | ||
2573 | |||
2426 | ehea_info("%s: Jumbo frames are %sabled", dev->name, | 2574 | ehea_info("%s: Jumbo frames are %sabled", dev->name, |
2427 | jumbo == 1 ? "en" : "dis"); | 2575 | jumbo == 1 ? "en" : "dis"); |
2428 | 2576 | ||
2429 | port->netdev = dev; | 2577 | return port; |
2430 | ret = 0; | ||
2431 | goto out; | ||
2432 | 2578 | ||
2433 | out_free: | 2579 | out_unreg_port: |
2580 | ehea_unregister_port(port); | ||
2581 | |||
2582 | out_free_mc_list: | ||
2434 | kfree(port->mc_list); | 2583 | kfree(port->mc_list); |
2435 | out: | 2584 | |
2436 | return ret; | 2585 | out_free_ethdev: |
2586 | free_netdev(dev); | ||
2587 | |||
2588 | out_err: | ||
2589 | ehea_error("setting up logical port with id=%d failed, ret=%d", | ||
2590 | logical_port_id, ret); | ||
2591 | return NULL; | ||
2592 | } | ||
2593 | |||
2594 | static void ehea_shutdown_single_port(struct ehea_port *port) | ||
2595 | { | ||
2596 | unregister_netdev(port->netdev); | ||
2597 | ehea_unregister_port(port); | ||
2598 | kfree(port->mc_list); | ||
2599 | free_netdev(port->netdev); | ||
2437 | } | 2600 | } |
2438 | 2601 | ||
2439 | static int ehea_setup_ports(struct ehea_adapter *adapter) | 2602 | static int ehea_setup_ports(struct ehea_adapter *adapter) |
2440 | { | 2603 | { |
2441 | int ret; | 2604 | struct device_node *lhea_dn; |
2442 | int port_setup_ok = 0; | 2605 | struct device_node *eth_dn = NULL; |
2606 | |||
2607 | u32 *dn_log_port_id; | ||
2608 | int i = 0; | ||
2609 | |||
2610 | lhea_dn = adapter->ebus_dev->ofdev.node; | ||
2611 | while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { | ||
2612 | |||
2613 | dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", | ||
2614 | NULL); | ||
2615 | if (!dn_log_port_id) { | ||
2616 | ehea_error("bad device node: eth_dn name=%s", | ||
2617 | eth_dn->full_name); | ||
2618 | continue; | ||
2619 | } | ||
2620 | |||
2621 | if (ehea_add_adapter_mr(adapter)) { | ||
2622 | ehea_error("creating MR failed"); | ||
2623 | of_node_put(eth_dn); | ||
2624 | return -EIO; | ||
2625 | } | ||
2626 | |||
2627 | adapter->port[i] = ehea_setup_single_port(adapter, | ||
2628 | *dn_log_port_id, | ||
2629 | eth_dn); | ||
2630 | if (adapter->port[i]) | ||
2631 | ehea_info("%s -> logical port id #%d", | ||
2632 | adapter->port[i]->netdev->name, | ||
2633 | *dn_log_port_id); | ||
2634 | else | ||
2635 | ehea_remove_adapter_mr(adapter); | ||
2636 | |||
2637 | i++; | ||
2638 | }; | ||
2639 | |||
2640 | return 0; | ||
2641 | } | ||
2642 | |||
2643 | static struct device_node *ehea_get_eth_dn(struct ehea_adapter *adapter, | ||
2644 | u32 logical_port_id) | ||
2645 | { | ||
2646 | struct device_node *lhea_dn; | ||
2647 | struct device_node *eth_dn = NULL; | ||
2648 | u32 *dn_log_port_id; | ||
2649 | |||
2650 | lhea_dn = adapter->ebus_dev->ofdev.node; | ||
2651 | while ((eth_dn = of_get_next_child(lhea_dn, eth_dn))) { | ||
2652 | |||
2653 | dn_log_port_id = (u32*)get_property(eth_dn, "ibm,hea-port-no", | ||
2654 | NULL); | ||
2655 | if (dn_log_port_id) | ||
2656 | if (*dn_log_port_id == logical_port_id) | ||
2657 | return eth_dn; | ||
2658 | }; | ||
2659 | |||
2660 | return NULL; | ||
2661 | } | ||
2662 | |||
2663 | static ssize_t ehea_probe_port(struct device *dev, | ||
2664 | struct device_attribute *attr, | ||
2665 | const char *buf, size_t count) | ||
2666 | { | ||
2667 | struct ehea_adapter *adapter = dev->driver_data; | ||
2443 | struct ehea_port *port; | 2668 | struct ehea_port *port; |
2444 | struct device_node *dn = NULL; | 2669 | struct device_node *eth_dn = NULL; |
2445 | struct net_device *dev; | ||
2446 | int i; | 2670 | int i; |
2447 | 2671 | ||
2448 | /* get port properties for all ports */ | 2672 | u32 logical_port_id; |
2449 | for (i = 0; i < adapter->num_ports; i++) { | ||
2450 | 2673 | ||
2451 | if (adapter->port[i]) | 2674 | sscanf(buf, "%X", &logical_port_id); |
2452 | continue; /* port already up and running */ | ||
2453 | 2675 | ||
2454 | /* allocate memory for the port structures */ | 2676 | port = ehea_get_port(adapter, logical_port_id); |
2455 | dev = alloc_etherdev(sizeof(struct ehea_port)); | ||
2456 | 2677 | ||
2457 | if (!dev) { | 2678 | if (port) { |
2458 | ehea_error("no mem for net_device"); | 2679 | ehea_info("adding port with logical port id=%d failed. port " |
2459 | break; | 2680 | "already configured as %s.", logical_port_id, |
2460 | } | 2681 | port->netdev->name); |
2682 | return -EINVAL; | ||
2683 | } | ||
2461 | 2684 | ||
2462 | port = netdev_priv(dev); | 2685 | eth_dn = ehea_get_eth_dn(adapter, logical_port_id); |
2463 | port->adapter = adapter; | ||
2464 | port->netdev = dev; | ||
2465 | adapter->port[i] = port; | ||
2466 | port->msg_enable = netif_msg_init(msg_level, EHEA_MSG_DEFAULT); | ||
2467 | 2686 | ||
2468 | dn = of_find_node_by_name(dn, "ethernet"); | 2687 | if (!eth_dn) { |
2469 | ret = ehea_setup_single_port(port, dn); | 2688 | ehea_info("no logical port with id %d found", logical_port_id); |
2470 | if (ret) { | 2689 | return -EINVAL; |
2471 | /* Free mem for this port struct. The others will be | ||
2472 | processed on rollback */ | ||
2473 | free_netdev(dev); | ||
2474 | adapter->port[i] = NULL; | ||
2475 | ehea_error("eHEA port %d setup failed, ret=%d", i, ret); | ||
2476 | } | ||
2477 | } | 2690 | } |
2478 | 2691 | ||
2479 | of_node_put(dn); | 2692 | if (ehea_add_adapter_mr(adapter)) { |
2693 | ehea_error("creating MR failed"); | ||
2694 | return -EIO; | ||
2695 | } | ||
2480 | 2696 | ||
2481 | /* Check for succesfully set up ports */ | 2697 | port = ehea_setup_single_port(adapter, logical_port_id, eth_dn); |
2482 | for (i = 0; i < adapter->num_ports; i++) | ||
2483 | if (adapter->port[i]) | ||
2484 | port_setup_ok++; | ||
2485 | 2698 | ||
2486 | if (port_setup_ok) | 2699 | of_node_put(eth_dn); |
2487 | ret = 0; /* At least some ports are setup correctly */ | 2700 | |
2488 | else | 2701 | if (port) { |
2489 | ret = -EINVAL; | 2702 | for (i=0; i < EHEA_MAX_PORTS; i++) |
2703 | if (!adapter->port[i]) { | ||
2704 | adapter->port[i] = port; | ||
2705 | break; | ||
2706 | } | ||
2707 | |||
2708 | ehea_info("added %s (logical port id=%d)", port->netdev->name, | ||
2709 | logical_port_id); | ||
2710 | } else { | ||
2711 | ehea_remove_adapter_mr(adapter); | ||
2712 | return -EIO; | ||
2713 | } | ||
2714 | |||
2715 | return (ssize_t) count; | ||
2716 | } | ||
2717 | |||
2718 | static ssize_t ehea_remove_port(struct device *dev, | ||
2719 | struct device_attribute *attr, | ||
2720 | const char *buf, size_t count) | ||
2721 | { | ||
2722 | struct ehea_adapter *adapter = dev->driver_data; | ||
2723 | struct ehea_port *port; | ||
2724 | int i; | ||
2725 | u32 logical_port_id; | ||
2726 | |||
2727 | sscanf(buf, "%X", &logical_port_id); | ||
2728 | |||
2729 | port = ehea_get_port(adapter, logical_port_id); | ||
2730 | |||
2731 | if (port) { | ||
2732 | ehea_info("removed %s (logical port id=%d)", port->netdev->name, | ||
2733 | logical_port_id); | ||
2734 | |||
2735 | ehea_shutdown_single_port(port); | ||
2736 | |||
2737 | for (i=0; i < EHEA_MAX_PORTS; i++) | ||
2738 | if (adapter->port[i] == port) { | ||
2739 | adapter->port[i] = NULL; | ||
2740 | break; | ||
2741 | } | ||
2742 | } else { | ||
2743 | ehea_error("removing port with logical port id=%d failed. port " | ||
2744 | "not configured.", logical_port_id); | ||
2745 | return -EINVAL; | ||
2746 | } | ||
2747 | |||
2748 | ehea_remove_adapter_mr(adapter); | ||
2749 | |||
2750 | return (ssize_t) count; | ||
2751 | } | ||
2752 | |||
2753 | static DEVICE_ATTR(probe_port, S_IWUSR, NULL, ehea_probe_port); | ||
2754 | static DEVICE_ATTR(remove_port, S_IWUSR, NULL, ehea_remove_port); | ||
2490 | 2755 | ||
2756 | int ehea_create_device_sysfs(struct ibmebus_dev *dev) | ||
2757 | { | ||
2758 | int ret = device_create_file(&dev->ofdev.dev, &dev_attr_probe_port); | ||
2759 | if (ret) | ||
2760 | goto out; | ||
2761 | |||
2762 | ret = device_create_file(&dev->ofdev.dev, &dev_attr_remove_port); | ||
2763 | out: | ||
2491 | return ret; | 2764 | return ret; |
2492 | } | 2765 | } |
2493 | 2766 | ||
2494 | static int __devinit ehea_probe(struct ibmebus_dev *dev, | 2767 | void ehea_remove_device_sysfs(struct ibmebus_dev *dev) |
2495 | const struct of_device_id *id) | 2768 | { |
2769 | device_remove_file(&dev->ofdev.dev, &dev_attr_probe_port); | ||
2770 | device_remove_file(&dev->ofdev.dev, &dev_attr_remove_port); | ||
2771 | } | ||
2772 | |||
2773 | static int __devinit ehea_probe_adapter(struct ibmebus_dev *dev, | ||
2774 | const struct of_device_id *id) | ||
2496 | { | 2775 | { |
2497 | struct ehea_adapter *adapter; | 2776 | struct ehea_adapter *adapter; |
2498 | u64 *adapter_handle; | 2777 | u64 *adapter_handle; |
2499 | int ret; | 2778 | int ret; |
2500 | 2779 | ||
2780 | if (!dev || !dev->ofdev.node) { | ||
2781 | ehea_error("Invalid ibmebus device probed"); | ||
2782 | return -EINVAL; | ||
2783 | } | ||
2784 | |||
2501 | adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); | 2785 | adapter = kzalloc(sizeof(*adapter), GFP_KERNEL); |
2502 | if (!adapter) { | 2786 | if (!adapter) { |
2503 | ret = -ENOMEM; | 2787 | ret = -ENOMEM; |
@@ -2505,6 +2789,8 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, | |||
2505 | goto out; | 2789 | goto out; |
2506 | } | 2790 | } |
2507 | 2791 | ||
2792 | adapter->ebus_dev = dev; | ||
2793 | |||
2508 | adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", | 2794 | adapter_handle = (u64*)get_property(dev->ofdev.node, "ibm,hea-handle", |
2509 | NULL); | 2795 | NULL); |
2510 | if (adapter_handle) | 2796 | if (adapter_handle) |
@@ -2521,26 +2807,21 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, | |||
2521 | 2807 | ||
2522 | dev->ofdev.dev.driver_data = adapter; | 2808 | dev->ofdev.dev.driver_data = adapter; |
2523 | 2809 | ||
2524 | ret = ehea_reg_mr_adapter(adapter); | ||
2525 | if (ret) { | ||
2526 | dev_err(&dev->ofdev.dev, "reg_mr_adapter failed\n"); | ||
2527 | goto out_free_ad; | ||
2528 | } | ||
2529 | 2810 | ||
2530 | /* initialize adapter and ports */ | 2811 | /* initialize adapter and ports */ |
2531 | /* get adapter properties */ | 2812 | /* get adapter properties */ |
2532 | ret = ehea_sense_adapter_attr(adapter); | 2813 | ret = ehea_sense_adapter_attr(adapter); |
2533 | if (ret) { | 2814 | if (ret) { |
2534 | dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret); | 2815 | dev_err(&dev->ofdev.dev, "sense_adapter_attr failed: %d", ret); |
2535 | goto out_free_res; | 2816 | goto out_free_ad; |
2536 | } | 2817 | } |
2537 | dev_info(&dev->ofdev.dev, "%d eHEA ports found\n", adapter->num_ports); | ||
2538 | 2818 | ||
2539 | adapter->neq = ehea_create_eq(adapter, | 2819 | adapter->neq = ehea_create_eq(adapter, |
2540 | EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); | 2820 | EHEA_NEQ, EHEA_MAX_ENTRIES_EQ, 1); |
2541 | if (!adapter->neq) { | 2821 | if (!adapter->neq) { |
2822 | ret = -EIO; | ||
2542 | dev_err(&dev->ofdev.dev, "NEQ creation failed"); | 2823 | dev_err(&dev->ofdev.dev, "NEQ creation failed"); |
2543 | goto out_free_res; | 2824 | goto out_free_ad; |
2544 | } | 2825 | } |
2545 | 2826 | ||
2546 | tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet, | 2827 | tasklet_init(&adapter->neq_tasklet, ehea_neq_tasklet, |
@@ -2555,18 +2836,27 @@ static int __devinit ehea_probe(struct ibmebus_dev *dev, | |||
2555 | } | 2836 | } |
2556 | 2837 | ||
2557 | adapter->ehea_wq = create_workqueue("ehea_wq"); | 2838 | adapter->ehea_wq = create_workqueue("ehea_wq"); |
2558 | if (!adapter->ehea_wq) | 2839 | if (!adapter->ehea_wq) { |
2840 | ret = -EIO; | ||
2559 | goto out_free_irq; | 2841 | goto out_free_irq; |
2842 | } | ||
2843 | |||
2844 | ret = ehea_create_device_sysfs(dev); | ||
2845 | if (ret) | ||
2846 | goto out_kill_wq; | ||
2560 | 2847 | ||
2561 | ret = ehea_setup_ports(adapter); | 2848 | ret = ehea_setup_ports(adapter); |
2562 | if (ret) { | 2849 | if (ret) { |
2563 | dev_err(&dev->ofdev.dev, "setup_ports failed"); | 2850 | dev_err(&dev->ofdev.dev, "setup_ports failed"); |
2564 | goto out_kill_wq; | 2851 | goto out_rem_dev_sysfs; |
2565 | } | 2852 | } |
2566 | 2853 | ||
2567 | ret = 0; | 2854 | ret = 0; |
2568 | goto out; | 2855 | goto out; |
2569 | 2856 | ||
2857 | out_rem_dev_sysfs: | ||
2858 | ehea_remove_device_sysfs(dev); | ||
2859 | |||
2570 | out_kill_wq: | 2860 | out_kill_wq: |
2571 | destroy_workqueue(adapter->ehea_wq); | 2861 | destroy_workqueue(adapter->ehea_wq); |
2572 | 2862 | ||
@@ -2576,45 +2866,32 @@ out_free_irq: | |||
2576 | out_kill_eq: | 2866 | out_kill_eq: |
2577 | ehea_destroy_eq(adapter->neq); | 2867 | ehea_destroy_eq(adapter->neq); |
2578 | 2868 | ||
2579 | out_free_res: | ||
2580 | ehea_h_free_resource(adapter->handle, adapter->mr.handle); | ||
2581 | |||
2582 | out_free_ad: | 2869 | out_free_ad: |
2583 | kfree(adapter); | 2870 | kfree(adapter); |
2584 | out: | 2871 | out: |
2585 | return ret; | 2872 | return ret; |
2586 | } | 2873 | } |
2587 | 2874 | ||
2588 | static void ehea_shutdown_single_port(struct ehea_port *port) | ||
2589 | { | ||
2590 | unregister_netdev(port->netdev); | ||
2591 | kfree(port->mc_list); | ||
2592 | free_netdev(port->netdev); | ||
2593 | } | ||
2594 | |||
2595 | static int __devexit ehea_remove(struct ibmebus_dev *dev) | 2875 | static int __devexit ehea_remove(struct ibmebus_dev *dev) |
2596 | { | 2876 | { |
2597 | struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; | 2877 | struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; |
2598 | u64 hret; | ||
2599 | int i; | 2878 | int i; |
2600 | 2879 | ||
2601 | for (i = 0; i < adapter->num_ports; i++) | 2880 | for (i = 0; i < EHEA_MAX_PORTS; i++) |
2602 | if (adapter->port[i]) { | 2881 | if (adapter->port[i]) { |
2603 | ehea_shutdown_single_port(adapter->port[i]); | 2882 | ehea_shutdown_single_port(adapter->port[i]); |
2604 | adapter->port[i] = NULL; | 2883 | adapter->port[i] = NULL; |
2605 | } | 2884 | } |
2885 | |||
2886 | ehea_remove_device_sysfs(dev); | ||
2887 | |||
2606 | destroy_workqueue(adapter->ehea_wq); | 2888 | destroy_workqueue(adapter->ehea_wq); |
2607 | 2889 | ||
2608 | ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); | 2890 | ibmebus_free_irq(NULL, adapter->neq->attr.ist1, adapter); |
2609 | tasklet_kill(&adapter->neq_tasklet); | 2891 | tasklet_kill(&adapter->neq_tasklet); |
2610 | 2892 | ||
2611 | ehea_destroy_eq(adapter->neq); | 2893 | ehea_destroy_eq(adapter->neq); |
2612 | 2894 | ehea_remove_adapter_mr(adapter); | |
2613 | hret = ehea_h_free_resource(adapter->handle, adapter->mr.handle); | ||
2614 | if (hret) { | ||
2615 | dev_err(&dev->ofdev.dev, "free_resource_mr failed"); | ||
2616 | return -EIO; | ||
2617 | } | ||
2618 | kfree(adapter); | 2895 | kfree(adapter); |
2619 | return 0; | 2896 | return 0; |
2620 | } | 2897 | } |
@@ -2647,21 +2924,6 @@ static int check_module_parm(void) | |||
2647 | return ret; | 2924 | return ret; |
2648 | } | 2925 | } |
2649 | 2926 | ||
2650 | static struct of_device_id ehea_device_table[] = { | ||
2651 | { | ||
2652 | .name = "lhea", | ||
2653 | .compatible = "IBM,lhea", | ||
2654 | }, | ||
2655 | {}, | ||
2656 | }; | ||
2657 | |||
2658 | static struct ibmebus_driver ehea_driver = { | ||
2659 | .name = "ehea", | ||
2660 | .id_table = ehea_device_table, | ||
2661 | .probe = ehea_probe, | ||
2662 | .remove = ehea_remove, | ||
2663 | }; | ||
2664 | |||
2665 | int __init ehea_module_init(void) | 2927 | int __init ehea_module_init(void) |
2666 | { | 2928 | { |
2667 | int ret; | 2929 | int ret; |
diff --git a/drivers/net/ehea/ehea_phyp.c b/drivers/net/ehea/ehea_phyp.c index bc3c00547264..95c4a7f9cc88 100644 --- a/drivers/net/ehea/ehea_phyp.c +++ b/drivers/net/ehea/ehea_phyp.c | |||
@@ -478,12 +478,14 @@ u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle) | |||
478 | 0, 0, 0, 0, 0, 0); /* R7-R12 */ | 478 | 0, 0, 0, 0, 0, 0); /* R7-R12 */ |
479 | } | 479 | } |
480 | 480 | ||
481 | u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle) | 481 | u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle, |
482 | u64 force_bit) | ||
482 | { | 483 | { |
483 | return ehea_plpar_hcall_norets(H_FREE_RESOURCE, | 484 | return ehea_plpar_hcall_norets(H_FREE_RESOURCE, |
484 | adapter_handle, /* R4 */ | 485 | adapter_handle, /* R4 */ |
485 | res_handle, /* R5 */ | 486 | res_handle, /* R5 */ |
486 | 0, 0, 0, 0, 0); /* R6-R10 */ | 487 | force_bit, |
488 | 0, 0, 0, 0); /* R7-R10 */ | ||
487 | } | 489 | } |
488 | 490 | ||
489 | u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, | 491 | u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, |
diff --git a/drivers/net/ehea/ehea_phyp.h b/drivers/net/ehea/ehea_phyp.h index 90acddb068a1..d17a45a7e717 100644 --- a/drivers/net/ehea/ehea_phyp.h +++ b/drivers/net/ehea/ehea_phyp.h | |||
@@ -414,7 +414,11 @@ u64 ehea_h_register_rpage(const u64 adapter_handle, | |||
414 | 414 | ||
415 | u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle); | 415 | u64 ehea_h_disable_and_get_hea(const u64 adapter_handle, const u64 qp_handle); |
416 | 416 | ||
417 | u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle); | 417 | #define FORCE_FREE 1 |
418 | #define NORMAL_FREE 0 | ||
419 | |||
420 | u64 ehea_h_free_resource(const u64 adapter_handle, const u64 res_handle, | ||
421 | u64 force_bit); | ||
418 | 422 | ||
419 | u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, | 423 | u64 ehea_h_alloc_resource_mr(const u64 adapter_handle, const u64 vaddr, |
420 | const u64 length, const u32 access_ctrl, | 424 | const u64 length, const u32 access_ctrl, |
diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 96ff3b679996..f24a8862977d 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c | |||
@@ -197,7 +197,7 @@ out_kill_hwq: | |||
197 | hw_queue_dtor(&cq->hw_queue); | 197 | hw_queue_dtor(&cq->hw_queue); |
198 | 198 | ||
199 | out_freeres: | 199 | out_freeres: |
200 | ehea_h_free_resource(adapter->handle, cq->fw_handle); | 200 | ehea_h_free_resource(adapter->handle, cq->fw_handle, FORCE_FREE); |
201 | 201 | ||
202 | out_freemem: | 202 | out_freemem: |
203 | kfree(cq); | 203 | kfree(cq); |
@@ -206,25 +206,38 @@ out_nomem: | |||
206 | return NULL; | 206 | return NULL; |
207 | } | 207 | } |
208 | 208 | ||
209 | int ehea_destroy_cq(struct ehea_cq *cq) | 209 | u64 ehea_destroy_cq_res(struct ehea_cq *cq, u64 force) |
210 | { | 210 | { |
211 | u64 adapter_handle, hret; | 211 | u64 hret; |
212 | u64 adapter_handle = cq->adapter->handle; | ||
213 | |||
214 | /* deregister all previous registered pages */ | ||
215 | hret = ehea_h_free_resource(adapter_handle, cq->fw_handle, force); | ||
216 | if (hret != H_SUCCESS) | ||
217 | return hret; | ||
218 | |||
219 | hw_queue_dtor(&cq->hw_queue); | ||
220 | kfree(cq); | ||
221 | |||
222 | return hret; | ||
223 | } | ||
212 | 224 | ||
225 | int ehea_destroy_cq(struct ehea_cq *cq) | ||
226 | { | ||
227 | u64 hret; | ||
213 | if (!cq) | 228 | if (!cq) |
214 | return 0; | 229 | return 0; |
215 | 230 | ||
216 | adapter_handle = cq->adapter->handle; | 231 | if ((hret = ehea_destroy_cq_res(cq, NORMAL_FREE)) == H_R_STATE) { |
232 | ehea_error_data(cq->adapter, cq->fw_handle); | ||
233 | hret = ehea_destroy_cq_res(cq, FORCE_FREE); | ||
234 | } | ||
217 | 235 | ||
218 | /* deregister all previous registered pages */ | ||
219 | hret = ehea_h_free_resource(adapter_handle, cq->fw_handle); | ||
220 | if (hret != H_SUCCESS) { | 236 | if (hret != H_SUCCESS) { |
221 | ehea_error("destroy CQ failed"); | 237 | ehea_error("destroy CQ failed"); |
222 | return -EIO; | 238 | return -EIO; |
223 | } | 239 | } |
224 | 240 | ||
225 | hw_queue_dtor(&cq->hw_queue); | ||
226 | kfree(cq); | ||
227 | |||
228 | return 0; | 241 | return 0; |
229 | } | 242 | } |
230 | 243 | ||
@@ -297,7 +310,7 @@ out_kill_hwq: | |||
297 | hw_queue_dtor(&eq->hw_queue); | 310 | hw_queue_dtor(&eq->hw_queue); |
298 | 311 | ||
299 | out_freeres: | 312 | out_freeres: |
300 | ehea_h_free_resource(adapter->handle, eq->fw_handle); | 313 | ehea_h_free_resource(adapter->handle, eq->fw_handle, FORCE_FREE); |
301 | 314 | ||
302 | out_freemem: | 315 | out_freemem: |
303 | kfree(eq); | 316 | kfree(eq); |
@@ -316,27 +329,41 @@ struct ehea_eqe *ehea_poll_eq(struct ehea_eq *eq) | |||
316 | return eqe; | 329 | return eqe; |
317 | } | 330 | } |
318 | 331 | ||
319 | int ehea_destroy_eq(struct ehea_eq *eq) | 332 | u64 ehea_destroy_eq_res(struct ehea_eq *eq, u64 force) |
320 | { | 333 | { |
321 | u64 hret; | 334 | u64 hret; |
322 | unsigned long flags; | 335 | unsigned long flags; |
323 | 336 | ||
324 | if (!eq) | ||
325 | return 0; | ||
326 | |||
327 | spin_lock_irqsave(&eq->spinlock, flags); | 337 | spin_lock_irqsave(&eq->spinlock, flags); |
328 | 338 | ||
329 | hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle); | 339 | hret = ehea_h_free_resource(eq->adapter->handle, eq->fw_handle, force); |
330 | spin_unlock_irqrestore(&eq->spinlock, flags); | 340 | spin_unlock_irqrestore(&eq->spinlock, flags); |
331 | 341 | ||
332 | if (hret != H_SUCCESS) { | 342 | if (hret != H_SUCCESS) |
333 | ehea_error("destroy_eq failed"); | 343 | return hret; |
334 | return -EIO; | ||
335 | } | ||
336 | 344 | ||
337 | hw_queue_dtor(&eq->hw_queue); | 345 | hw_queue_dtor(&eq->hw_queue); |
338 | kfree(eq); | 346 | kfree(eq); |
339 | 347 | ||
348 | return hret; | ||
349 | } | ||
350 | |||
351 | int ehea_destroy_eq(struct ehea_eq *eq) | ||
352 | { | ||
353 | u64 hret; | ||
354 | if (!eq) | ||
355 | return 0; | ||
356 | |||
357 | if ((hret = ehea_destroy_eq_res(eq, NORMAL_FREE)) == H_R_STATE) { | ||
358 | ehea_error_data(eq->adapter, eq->fw_handle); | ||
359 | hret = ehea_destroy_eq_res(eq, FORCE_FREE); | ||
360 | } | ||
361 | |||
362 | if (hret != H_SUCCESS) { | ||
363 | ehea_error("destroy EQ failed"); | ||
364 | return -EIO; | ||
365 | } | ||
366 | |||
340 | return 0; | 367 | return 0; |
341 | } | 368 | } |
342 | 369 | ||
@@ -471,41 +498,56 @@ out_kill_hwsq: | |||
471 | 498 | ||
472 | out_freeres: | 499 | out_freeres: |
473 | ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle); | 500 | ehea_h_disable_and_get_hea(adapter->handle, qp->fw_handle); |
474 | ehea_h_free_resource(adapter->handle, qp->fw_handle); | 501 | ehea_h_free_resource(adapter->handle, qp->fw_handle, FORCE_FREE); |
475 | 502 | ||
476 | out_freemem: | 503 | out_freemem: |
477 | kfree(qp); | 504 | kfree(qp); |
478 | return NULL; | 505 | return NULL; |
479 | } | 506 | } |
480 | 507 | ||
481 | int ehea_destroy_qp(struct ehea_qp *qp) | 508 | u64 ehea_destroy_qp_res(struct ehea_qp *qp, u64 force) |
482 | { | 509 | { |
483 | u64 hret; | 510 | u64 hret; |
484 | struct ehea_qp_init_attr *qp_attr = &qp->init_attr; | 511 | struct ehea_qp_init_attr *qp_attr = &qp->init_attr; |
485 | 512 | ||
486 | if (!qp) | ||
487 | return 0; | ||
488 | 513 | ||
489 | ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle); | 514 | ehea_h_disable_and_get_hea(qp->adapter->handle, qp->fw_handle); |
490 | hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle); | 515 | hret = ehea_h_free_resource(qp->adapter->handle, qp->fw_handle, force); |
491 | if (hret != H_SUCCESS) { | 516 | if (hret != H_SUCCESS) |
492 | ehea_error("destroy_qp failed"); | 517 | return hret; |
493 | return -EIO; | ||
494 | } | ||
495 | 518 | ||
496 | hw_queue_dtor(&qp->hw_squeue); | 519 | hw_queue_dtor(&qp->hw_squeue); |
497 | hw_queue_dtor(&qp->hw_rqueue1); | 520 | hw_queue_dtor(&qp->hw_rqueue1); |
498 | 521 | ||
499 | if (qp_attr->rq_count > 1) | 522 | if (qp_attr->rq_count > 1) |
500 | hw_queue_dtor(&qp->hw_rqueue2); | 523 | hw_queue_dtor(&qp->hw_rqueue2); |
501 | if (qp_attr->rq_count > 2) | 524 | if (qp_attr->rq_count > 2) |
502 | hw_queue_dtor(&qp->hw_rqueue3); | 525 | hw_queue_dtor(&qp->hw_rqueue3); |
503 | kfree(qp); | 526 | kfree(qp); |
504 | 527 | ||
505 | return 0; | 528 | return hret; |
506 | } | 529 | } |
507 | 530 | ||
508 | int ehea_reg_mr_adapter(struct ehea_adapter *adapter) | 531 | int ehea_destroy_qp(struct ehea_qp *qp) |
532 | { | ||
533 | u64 hret; | ||
534 | if (!qp) | ||
535 | return 0; | ||
536 | |||
537 | if ((hret = ehea_destroy_qp_res(qp, NORMAL_FREE)) == H_R_STATE) { | ||
538 | ehea_error_data(qp->adapter, qp->fw_handle); | ||
539 | hret = ehea_destroy_qp_res(qp, FORCE_FREE); | ||
540 | } | ||
541 | |||
542 | if (hret != H_SUCCESS) { | ||
543 | ehea_error("destroy QP failed"); | ||
544 | return -EIO; | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) | ||
509 | { | 551 | { |
510 | int i, k, ret; | 552 | int i, k, ret; |
511 | u64 hret, pt_abs, start, end, nr_pages; | 553 | u64 hret, pt_abs, start, end, nr_pages; |
@@ -526,14 +568,14 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter) | |||
526 | 568 | ||
527 | hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start, | 569 | hret = ehea_h_alloc_resource_mr(adapter->handle, start, end - start, |
528 | acc_ctrl, adapter->pd, | 570 | acc_ctrl, adapter->pd, |
529 | &adapter->mr.handle, &adapter->mr.lkey); | 571 | &mr->handle, &mr->lkey); |
530 | if (hret != H_SUCCESS) { | 572 | if (hret != H_SUCCESS) { |
531 | ehea_error("alloc_resource_mr failed"); | 573 | ehea_error("alloc_resource_mr failed"); |
532 | ret = -EIO; | 574 | ret = -EIO; |
533 | goto out; | 575 | goto out; |
534 | } | 576 | } |
535 | 577 | ||
536 | adapter->mr.vaddr = KERNELBASE; | 578 | mr->vaddr = KERNELBASE; |
537 | k = 0; | 579 | k = 0; |
538 | 580 | ||
539 | while (nr_pages > 0) { | 581 | while (nr_pages > 0) { |
@@ -545,7 +587,7 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter) | |||
545 | EHEA_PAGESIZE))); | 587 | EHEA_PAGESIZE))); |
546 | 588 | ||
547 | hret = ehea_h_register_rpage_mr(adapter->handle, | 589 | hret = ehea_h_register_rpage_mr(adapter->handle, |
548 | adapter->mr.handle, 0, | 590 | mr->handle, 0, |
549 | 0, (u64)pt_abs, | 591 | 0, (u64)pt_abs, |
550 | num_pages); | 592 | num_pages); |
551 | nr_pages -= num_pages; | 593 | nr_pages -= num_pages; |
@@ -554,34 +596,68 @@ int ehea_reg_mr_adapter(struct ehea_adapter *adapter) | |||
554 | (k * EHEA_PAGESIZE))); | 596 | (k * EHEA_PAGESIZE))); |
555 | 597 | ||
556 | hret = ehea_h_register_rpage_mr(adapter->handle, | 598 | hret = ehea_h_register_rpage_mr(adapter->handle, |
557 | adapter->mr.handle, 0, | 599 | mr->handle, 0, |
558 | 0, abs_adr,1); | 600 | 0, abs_adr,1); |
559 | nr_pages--; | 601 | nr_pages--; |
560 | } | 602 | } |
561 | 603 | ||
562 | if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) { | 604 | if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) { |
563 | ehea_h_free_resource(adapter->handle, | 605 | ehea_h_free_resource(adapter->handle, |
564 | adapter->mr.handle); | 606 | mr->handle, FORCE_FREE); |
565 | ehea_error("register_rpage_mr failed: hret = %lX", | 607 | ehea_error("register_rpage_mr failed"); |
566 | hret); | ||
567 | ret = -EIO; | 608 | ret = -EIO; |
568 | goto out; | 609 | goto out; |
569 | } | 610 | } |
570 | } | 611 | } |
571 | 612 | ||
572 | if (hret != H_SUCCESS) { | 613 | if (hret != H_SUCCESS) { |
573 | ehea_h_free_resource(adapter->handle, adapter->mr.handle); | 614 | ehea_h_free_resource(adapter->handle, mr->handle, |
574 | ehea_error("register_rpage failed for last page: hret = %lX", | 615 | FORCE_FREE); |
575 | hret); | 616 | ehea_error("register_rpage failed for last page"); |
576 | ret = -EIO; | 617 | ret = -EIO; |
577 | goto out; | 618 | goto out; |
578 | } | 619 | } |
620 | |||
621 | mr->adapter = adapter; | ||
579 | ret = 0; | 622 | ret = 0; |
580 | out: | 623 | out: |
581 | kfree(pt); | 624 | kfree(pt); |
582 | return ret; | 625 | return ret; |
583 | } | 626 | } |
584 | 627 | ||
628 | int ehea_rem_mr(struct ehea_mr *mr) | ||
629 | { | ||
630 | u64 hret; | ||
631 | |||
632 | if (!mr || !mr->adapter) | ||
633 | return -EINVAL; | ||
634 | |||
635 | hret = ehea_h_free_resource(mr->adapter->handle, mr->handle, | ||
636 | FORCE_FREE); | ||
637 | if (hret != H_SUCCESS) { | ||
638 | ehea_error("destroy MR failed"); | ||
639 | return -EIO; | ||
640 | } | ||
641 | |||
642 | return 0; | ||
643 | } | ||
644 | |||
645 | int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr, | ||
646 | struct ehea_mr *shared_mr) | ||
647 | { | ||
648 | u64 hret; | ||
649 | |||
650 | hret = ehea_h_register_smr(adapter->handle, old_mr->handle, | ||
651 | old_mr->vaddr, EHEA_MR_ACC_CTRL, | ||
652 | adapter->pd, shared_mr); | ||
653 | if (hret != H_SUCCESS) | ||
654 | return -EIO; | ||
655 | |||
656 | shared_mr->adapter = adapter; | ||
657 | |||
658 | return 0; | ||
659 | } | ||
660 | |||
585 | void print_error_data(u64 *data) | 661 | void print_error_data(u64 *data) |
586 | { | 662 | { |
587 | int length; | 663 | int length; |
@@ -597,6 +673,14 @@ void print_error_data(u64 *data) | |||
597 | ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, " | 673 | ehea_error("QP (resource=%lX) state: AER=0x%lX, AERR=0x%lX, " |
598 | "port=%lX", resource, data[6], data[12], data[22]); | 674 | "port=%lX", resource, data[6], data[12], data[22]); |
599 | 675 | ||
676 | if (type == 0x4) /* Completion Queue */ | ||
677 | ehea_error("CQ (resource=%lX) state: AER=0x%lX", resource, | ||
678 | data[6]); | ||
679 | |||
680 | if (type == 0x3) /* Event Queue */ | ||
681 | ehea_error("EQ (resource=%lX) state: AER=0x%lX", resource, | ||
682 | data[6]); | ||
683 | |||
600 | ehea_dump(data, length, "error data"); | 684 | ehea_dump(data, length, "error data"); |
601 | } | 685 | } |
602 | 686 | ||
diff --git a/drivers/net/ehea/ehea_qmr.h b/drivers/net/ehea/ehea_qmr.h index 1ff60983504d..c0eb3e03a102 100644 --- a/drivers/net/ehea/ehea_qmr.h +++ b/drivers/net/ehea/ehea_qmr.h | |||
@@ -142,6 +142,8 @@ struct ehea_rwqe { | |||
142 | #define EHEA_CQE_STAT_ERR_MASK 0x721F | 142 | #define EHEA_CQE_STAT_ERR_MASK 0x721F |
143 | #define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F | 143 | #define EHEA_CQE_STAT_FAT_ERR_MASK 0x1F |
144 | #define EHEA_CQE_STAT_ERR_TCP 0x4000 | 144 | #define EHEA_CQE_STAT_ERR_TCP 0x4000 |
145 | #define EHEA_CQE_STAT_ERR_IP 0x2000 | ||
146 | #define EHEA_CQE_STAT_ERR_CRC 0x1000 | ||
145 | 147 | ||
146 | struct ehea_cqe { | 148 | struct ehea_cqe { |
147 | u64 wr_id; /* work request ID from WQE */ | 149 | u64 wr_id; /* work request ID from WQE */ |
@@ -320,6 +322,11 @@ static inline struct ehea_cqe *ehea_poll_rq1(struct ehea_qp *qp, int *wqe_index) | |||
320 | return hw_qeit_get_valid(queue); | 322 | return hw_qeit_get_valid(queue); |
321 | } | 323 | } |
322 | 324 | ||
325 | static inline void ehea_inc_cq(struct ehea_cq *cq) | ||
326 | { | ||
327 | hw_qeit_inc(&cq->hw_queue); | ||
328 | } | ||
329 | |||
323 | static inline void ehea_inc_rq1(struct ehea_qp *qp) | 330 | static inline void ehea_inc_rq1(struct ehea_qp *qp) |
324 | { | 331 | { |
325 | hw_qeit_inc(&qp->hw_rqueue1); | 332 | hw_qeit_inc(&qp->hw_rqueue1); |
@@ -327,7 +334,7 @@ static inline void ehea_inc_rq1(struct ehea_qp *qp) | |||
327 | 334 | ||
328 | static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq) | 335 | static inline struct ehea_cqe *ehea_poll_cq(struct ehea_cq *my_cq) |
329 | { | 336 | { |
330 | return hw_qeit_get_inc_valid(&my_cq->hw_queue); | 337 | return hw_qeit_get_valid(&my_cq->hw_queue); |
331 | } | 338 | } |
332 | 339 | ||
333 | #define EHEA_CQ_REGISTER_ORIG 0 | 340 | #define EHEA_CQ_REGISTER_ORIG 0 |
@@ -356,7 +363,12 @@ struct ehea_qp *ehea_create_qp(struct ehea_adapter * adapter, u32 pd, | |||
356 | 363 | ||
357 | int ehea_destroy_qp(struct ehea_qp *qp); | 364 | int ehea_destroy_qp(struct ehea_qp *qp); |
358 | 365 | ||
359 | int ehea_reg_mr_adapter(struct ehea_adapter *adapter); | 366 | int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr); |
367 | |||
368 | int ehea_gen_smr(struct ehea_adapter *adapter, struct ehea_mr *old_mr, | ||
369 | struct ehea_mr *shared_mr); | ||
370 | |||
371 | int ehea_rem_mr(struct ehea_mr *mr); | ||
360 | 372 | ||
361 | void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); | 373 | void ehea_error_data(struct ehea_adapter *adapter, u64 res_handle); |
362 | 374 | ||
diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 30baf6ecfc63..17ac6975d70d 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c | |||
@@ -415,11 +415,18 @@ static int ser12_open(struct net_device *dev) | |||
415 | 415 | ||
416 | if (!dev || !bc) | 416 | if (!dev || !bc) |
417 | return -ENXIO; | 417 | return -ENXIO; |
418 | if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || | 418 | if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT || |
419 | dev->irq < 2 || dev->irq > 15) | 419 | dev->irq < 2 || dev->irq > NR_IRQS) { |
420 | printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) " | ||
421 | "or irq (2 <= irq <= %d)\n", | ||
422 | 0xffff-SER12_EXTENT, NR_IRQS); | ||
420 | return -ENXIO; | 423 | return -ENXIO; |
421 | if (bc->baud < 300 || bc->baud > 4800) | 424 | } |
425 | if (bc->baud < 300 || bc->baud > 4800) { | ||
426 | printk(KERN_INFO "baycom_ser_fdx: invalid baudrate " | ||
427 | "(300...4800)\n"); | ||
422 | return -EINVAL; | 428 | return -EINVAL; |
429 | } | ||
423 | if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) { | 430 | if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) { |
424 | printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n", | 431 | printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy \n", |
425 | dev->base_addr); | 432 | dev->base_addr); |
diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index 0573fcfcb2c4..3bec0f733f01 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c | |||
@@ -93,7 +93,7 @@ static void ibmveth_proc_unregister_driver(void); | |||
93 | static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); | 93 | static void ibmveth_proc_register_adapter(struct ibmveth_adapter *adapter); |
94 | static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); | 94 | static void ibmveth_proc_unregister_adapter(struct ibmveth_adapter *adapter); |
95 | static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance); | 95 | static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance); |
96 | static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); | 96 | static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter); |
97 | static struct kobj_type ktype_veth_pool; | 97 | static struct kobj_type ktype_veth_pool; |
98 | 98 | ||
99 | #ifdef CONFIG_PROC_FS | 99 | #ifdef CONFIG_PROC_FS |
@@ -389,7 +389,7 @@ static void ibmveth_rxq_recycle_buffer(struct ibmveth_adapter *adapter) | |||
389 | } | 389 | } |
390 | } | 390 | } |
391 | 391 | ||
392 | static inline void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) | 392 | static void ibmveth_rxq_harvest_buffer(struct ibmveth_adapter *adapter) |
393 | { | 393 | { |
394 | ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator); | 394 | ibmveth_remove_buffer_from_pool(adapter, adapter->rx_queue.queue_addr[adapter->rx_queue.index].correlator); |
395 | 395 | ||
@@ -953,14 +953,16 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ | |||
953 | ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n", | 953 | ibmveth_debug_printk_no_adapter("entering ibmveth_probe for UA 0x%x\n", |
954 | dev->unit_address); | 954 | dev->unit_address); |
955 | 955 | ||
956 | mac_addr_p = (unsigned char *) vio_get_attribute(dev, VETH_MAC_ADDR, 0); | 956 | mac_addr_p = (unsigned char *) vio_get_attribute(dev, |
957 | VETH_MAC_ADDR, NULL); | ||
957 | if(!mac_addr_p) { | 958 | if(!mac_addr_p) { |
958 | printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR " | 959 | printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find VETH_MAC_ADDR " |
959 | "attribute\n", __FILE__, __LINE__); | 960 | "attribute\n", __FILE__, __LINE__); |
960 | return 0; | 961 | return 0; |
961 | } | 962 | } |
962 | 963 | ||
963 | mcastFilterSize_p= (unsigned int *) vio_get_attribute(dev, VETH_MCAST_FILTER_SIZE, 0); | 964 | mcastFilterSize_p = (unsigned int *) vio_get_attribute(dev, |
965 | VETH_MCAST_FILTER_SIZE, NULL); | ||
964 | if(!mcastFilterSize_p) { | 966 | if(!mcastFilterSize_p) { |
965 | printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find " | 967 | printk(KERN_ERR "(%s:%3.3d) ERROR: Can't find " |
966 | "VETH_MCAST_FILTER_SIZE attribute\n", | 968 | "VETH_MCAST_FILTER_SIZE attribute\n", |
diff --git a/drivers/net/ixgb/ixgb.h b/drivers/net/ixgb/ixgb.h index cf30a1059ce0..c8e90861f869 100644 --- a/drivers/net/ixgb/ixgb.h +++ b/drivers/net/ixgb/ixgb.h | |||
@@ -111,9 +111,6 @@ struct ixgb_adapter; | |||
111 | /* How many Rx Buffers do we bundle into one write to the hardware ? */ | 111 | /* How many Rx Buffers do we bundle into one write to the hardware ? */ |
112 | #define IXGB_RX_BUFFER_WRITE 8 /* Must be power of 2 */ | 112 | #define IXGB_RX_BUFFER_WRITE 8 /* Must be power of 2 */ |
113 | 113 | ||
114 | /* only works for sizes that are powers of 2 */ | ||
115 | #define IXGB_ROUNDUP(i, size) ((i) = (((i) + (size) - 1) & ~((size) - 1))) | ||
116 | |||
117 | /* wrapper around a pointer to a socket buffer, | 114 | /* wrapper around a pointer to a socket buffer, |
118 | * so a DMA handle can be stored along with the buffer */ | 115 | * so a DMA handle can be stored along with the buffer */ |
119 | struct ixgb_buffer { | 116 | struct ixgb_buffer { |
diff --git a/drivers/net/ixgb/ixgb_ethtool.c b/drivers/net/ixgb/ixgb_ethtool.c index d6628bd9590a..afde84868bea 100644 --- a/drivers/net/ixgb/ixgb_ethtool.c +++ b/drivers/net/ixgb/ixgb_ethtool.c | |||
@@ -577,11 +577,11 @@ ixgb_set_ringparam(struct net_device *netdev, | |||
577 | 577 | ||
578 | rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD); | 578 | rxdr->count = max(ring->rx_pending,(uint32_t)MIN_RXD); |
579 | rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD); | 579 | rxdr->count = min(rxdr->count,(uint32_t)MAX_RXD); |
580 | IXGB_ROUNDUP(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); | 580 | rxdr->count = ALIGN(rxdr->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); |
581 | 581 | ||
582 | txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD); | 582 | txdr->count = max(ring->tx_pending,(uint32_t)MIN_TXD); |
583 | txdr->count = min(txdr->count,(uint32_t)MAX_TXD); | 583 | txdr->count = min(txdr->count,(uint32_t)MAX_TXD); |
584 | IXGB_ROUNDUP(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); | 584 | txdr->count = ALIGN(txdr->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); |
585 | 585 | ||
586 | if(netif_running(adapter->netdev)) { | 586 | if(netif_running(adapter->netdev)) { |
587 | /* Try to get new resources before deleting old */ | 587 | /* Try to get new resources before deleting old */ |
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index dfde80e54aef..6d2b059371f1 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c | |||
@@ -685,7 +685,7 @@ ixgb_setup_tx_resources(struct ixgb_adapter *adapter) | |||
685 | /* round up to nearest 4K */ | 685 | /* round up to nearest 4K */ |
686 | 686 | ||
687 | txdr->size = txdr->count * sizeof(struct ixgb_tx_desc); | 687 | txdr->size = txdr->count * sizeof(struct ixgb_tx_desc); |
688 | IXGB_ROUNDUP(txdr->size, 4096); | 688 | txdr->size = ALIGN(txdr->size, 4096); |
689 | 689 | ||
690 | txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); | 690 | txdr->desc = pci_alloc_consistent(pdev, txdr->size, &txdr->dma); |
691 | if(!txdr->desc) { | 691 | if(!txdr->desc) { |
@@ -774,7 +774,7 @@ ixgb_setup_rx_resources(struct ixgb_adapter *adapter) | |||
774 | /* Round up to nearest 4K */ | 774 | /* Round up to nearest 4K */ |
775 | 775 | ||
776 | rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc); | 776 | rxdr->size = rxdr->count * sizeof(struct ixgb_rx_desc); |
777 | IXGB_ROUNDUP(rxdr->size, 4096); | 777 | rxdr->size = ALIGN(rxdr->size, 4096); |
778 | 778 | ||
779 | rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); | 779 | rxdr->desc = pci_alloc_consistent(pdev, rxdr->size, &rxdr->dma); |
780 | 780 | ||
diff --git a/drivers/net/ixgb/ixgb_param.c b/drivers/net/ixgb/ixgb_param.c index b27442a121f2..5d5ddabf4360 100644 --- a/drivers/net/ixgb/ixgb_param.c +++ b/drivers/net/ixgb/ixgb_param.c | |||
@@ -245,8 +245,6 @@ ixgb_validate_option(int *value, struct ixgb_option *opt) | |||
245 | return -1; | 245 | return -1; |
246 | } | 246 | } |
247 | 247 | ||
248 | #define LIST_LEN(l) (sizeof(l) / sizeof(l[0])) | ||
249 | |||
250 | /** | 248 | /** |
251 | * ixgb_check_options - Range Checking for Command Line Parameters | 249 | * ixgb_check_options - Range Checking for Command Line Parameters |
252 | * @adapter: board private structure | 250 | * @adapter: board private structure |
@@ -284,7 +282,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) | |||
284 | } else { | 282 | } else { |
285 | tx_ring->count = opt.def; | 283 | tx_ring->count = opt.def; |
286 | } | 284 | } |
287 | IXGB_ROUNDUP(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); | 285 | tx_ring->count = ALIGN(tx_ring->count, IXGB_REQ_TX_DESCRIPTOR_MULTIPLE); |
288 | } | 286 | } |
289 | { /* Receive Descriptor Count */ | 287 | { /* Receive Descriptor Count */ |
290 | struct ixgb_option opt = { | 288 | struct ixgb_option opt = { |
@@ -303,7 +301,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) | |||
303 | } else { | 301 | } else { |
304 | rx_ring->count = opt.def; | 302 | rx_ring->count = opt.def; |
305 | } | 303 | } |
306 | IXGB_ROUNDUP(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); | 304 | rx_ring->count = ALIGN(rx_ring->count, IXGB_REQ_RX_DESCRIPTOR_MULTIPLE); |
307 | } | 305 | } |
308 | { /* Receive Checksum Offload Enable */ | 306 | { /* Receive Checksum Offload Enable */ |
309 | struct ixgb_option opt = { | 307 | struct ixgb_option opt = { |
@@ -335,7 +333,7 @@ ixgb_check_options(struct ixgb_adapter *adapter) | |||
335 | .name = "Flow Control", | 333 | .name = "Flow Control", |
336 | .err = "reading default settings from EEPROM", | 334 | .err = "reading default settings from EEPROM", |
337 | .def = ixgb_fc_tx_pause, | 335 | .def = ixgb_fc_tx_pause, |
338 | .arg = { .l = { .nr = LIST_LEN(fc_list), | 336 | .arg = { .l = { .nr = ARRAY_SIZE(fc_list), |
339 | .p = fc_list }} | 337 | .p = fc_list }} |
340 | }; | 338 | }; |
341 | 339 | ||
diff --git a/drivers/net/mii.c b/drivers/net/mii.c index 2912a34f597b..92056051f269 100644 --- a/drivers/net/mii.c +++ b/drivers/net/mii.c | |||
@@ -33,6 +33,13 @@ | |||
33 | #include <linux/ethtool.h> | 33 | #include <linux/ethtool.h> |
34 | #include <linux/mii.h> | 34 | #include <linux/mii.h> |
35 | 35 | ||
36 | /** | ||
37 | * mii_ethtool_gset - get settings that are specified in @ecmd | ||
38 | * @mii: MII interface | ||
39 | * @ecmd: requested ethtool_cmd | ||
40 | * | ||
41 | * Returns 0 for success, negative on error. | ||
42 | */ | ||
36 | int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) | 43 | int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) |
37 | { | 44 | { |
38 | struct net_device *dev = mii->dev; | 45 | struct net_device *dev = mii->dev; |
@@ -114,6 +121,13 @@ int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) | |||
114 | return 0; | 121 | return 0; |
115 | } | 122 | } |
116 | 123 | ||
124 | /** | ||
125 | * mii_ethtool_sset - set settings that are specified in @ecmd | ||
126 | * @mii: MII interface | ||
127 | * @ecmd: requested ethtool_cmd | ||
128 | * | ||
129 | * Returns 0 for success, negative on error. | ||
130 | */ | ||
117 | int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) | 131 | int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) |
118 | { | 132 | { |
119 | struct net_device *dev = mii->dev; | 133 | struct net_device *dev = mii->dev; |
@@ -207,6 +221,10 @@ int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) | |||
207 | return 0; | 221 | return 0; |
208 | } | 222 | } |
209 | 223 | ||
224 | /** | ||
225 | * mii_check_gmii_support - check if the MII supports Gb interfaces | ||
226 | * @mii: the MII interface | ||
227 | */ | ||
210 | int mii_check_gmii_support(struct mii_if_info *mii) | 228 | int mii_check_gmii_support(struct mii_if_info *mii) |
211 | { | 229 | { |
212 | int reg; | 230 | int reg; |
@@ -221,6 +239,12 @@ int mii_check_gmii_support(struct mii_if_info *mii) | |||
221 | return 0; | 239 | return 0; |
222 | } | 240 | } |
223 | 241 | ||
242 | /** | ||
243 | * mii_link_ok - is link status up/ok | ||
244 | * @mii: the MII interface | ||
245 | * | ||
246 | * Returns 1 if the MII reports link status up/ok, 0 otherwise. | ||
247 | */ | ||
224 | int mii_link_ok (struct mii_if_info *mii) | 248 | int mii_link_ok (struct mii_if_info *mii) |
225 | { | 249 | { |
226 | /* first, a dummy read, needed to latch some MII phys */ | 250 | /* first, a dummy read, needed to latch some MII phys */ |
@@ -230,6 +254,12 @@ int mii_link_ok (struct mii_if_info *mii) | |||
230 | return 0; | 254 | return 0; |
231 | } | 255 | } |
232 | 256 | ||
257 | /** | ||
258 | * mii_nway_restart - restart NWay (autonegotiation) for this interface | ||
259 | * @mii: the MII interface | ||
260 | * | ||
261 | * Returns 0 on success, negative on error. | ||
262 | */ | ||
233 | int mii_nway_restart (struct mii_if_info *mii) | 263 | int mii_nway_restart (struct mii_if_info *mii) |
234 | { | 264 | { |
235 | int bmcr; | 265 | int bmcr; |
@@ -247,6 +277,14 @@ int mii_nway_restart (struct mii_if_info *mii) | |||
247 | return r; | 277 | return r; |
248 | } | 278 | } |
249 | 279 | ||
280 | /** | ||
281 | * mii_check_link - check MII link status | ||
282 | * @mii: MII interface | ||
283 | * | ||
284 | * If the link status changed (previous != current), call | ||
285 | * netif_carrier_on() if current link status is Up or call | ||
286 | * netif_carrier_off() if current link status is Down. | ||
287 | */ | ||
250 | void mii_check_link (struct mii_if_info *mii) | 288 | void mii_check_link (struct mii_if_info *mii) |
251 | { | 289 | { |
252 | int cur_link = mii_link_ok(mii); | 290 | int cur_link = mii_link_ok(mii); |
@@ -258,6 +296,15 @@ void mii_check_link (struct mii_if_info *mii) | |||
258 | netif_carrier_off(mii->dev); | 296 | netif_carrier_off(mii->dev); |
259 | } | 297 | } |
260 | 298 | ||
299 | /** | ||
300 | * mii_check_media - check the MII interface for a duplex change | ||
301 | * @mii: the MII interface | ||
302 | * @ok_to_print: OK to print link up/down messages | ||
303 | * @init_media: OK to save duplex mode in @mii | ||
304 | * | ||
305 | * Returns 1 if the duplex mode changed, 0 if not. | ||
306 | * If the media type is forced, always returns 0. | ||
307 | */ | ||
261 | unsigned int mii_check_media (struct mii_if_info *mii, | 308 | unsigned int mii_check_media (struct mii_if_info *mii, |
262 | unsigned int ok_to_print, | 309 | unsigned int ok_to_print, |
263 | unsigned int init_media) | 310 | unsigned int init_media) |
@@ -326,6 +373,16 @@ unsigned int mii_check_media (struct mii_if_info *mii, | |||
326 | return 0; /* duplex did not change */ | 373 | return 0; /* duplex did not change */ |
327 | } | 374 | } |
328 | 375 | ||
376 | /** | ||
377 | * generic_mii_ioctl - main MII ioctl interface | ||
378 | * @mii_if: the MII interface | ||
379 | * @mii_data: MII ioctl data structure | ||
380 | * @cmd: MII ioctl command | ||
381 | * @duplex_chg_out: pointer to @duplex_changed status if there was no | ||
382 | * ioctl error | ||
383 | * | ||
384 | * Returns 0 on success, negative on error. | ||
385 | */ | ||
329 | int generic_mii_ioctl(struct mii_if_info *mii_if, | 386 | int generic_mii_ioctl(struct mii_if_info *mii_if, |
330 | struct mii_ioctl_data *mii_data, int cmd, | 387 | struct mii_ioctl_data *mii_data, int cmd, |
331 | unsigned int *duplex_chg_out) | 388 | unsigned int *duplex_chg_out) |
diff --git a/drivers/net/mipsnet.c b/drivers/net/mipsnet.c index 403f63afd201..638a279ec505 100644 --- a/drivers/net/mipsnet.c +++ b/drivers/net/mipsnet.c | |||
@@ -26,8 +26,6 @@ struct mipsnet_priv { | |||
26 | struct net_device_stats stats; | 26 | struct net_device_stats stats; |
27 | }; | 27 | }; |
28 | 28 | ||
29 | static struct platform_device *mips_plat_dev; | ||
30 | |||
31 | static char mipsnet_string[] = "mipsnet"; | 29 | static char mipsnet_string[] = "mipsnet"; |
32 | 30 | ||
33 | /* | 31 | /* |
@@ -297,64 +295,17 @@ static struct device_driver mipsnet_driver = { | |||
297 | .remove = __devexit_p(mipsnet_device_remove), | 295 | .remove = __devexit_p(mipsnet_device_remove), |
298 | }; | 296 | }; |
299 | 297 | ||
300 | static void mipsnet_platform_release(struct device *device) | ||
301 | { | ||
302 | struct platform_device *pldev; | ||
303 | |||
304 | /* free device */ | ||
305 | pldev = to_platform_device(device); | ||
306 | kfree(pldev); | ||
307 | } | ||
308 | |||
309 | static int __init mipsnet_init_module(void) | 298 | static int __init mipsnet_init_module(void) |
310 | { | 299 | { |
311 | struct platform_device *pldev; | ||
312 | int err; | 300 | int err; |
313 | 301 | ||
314 | printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. " | 302 | printk(KERN_INFO "MIPSNet Ethernet driver. Version: %s. " |
315 | "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION); | 303 | "(c)2005 MIPS Technologies, Inc.\n", MIPSNET_VERSION); |
316 | 304 | ||
317 | if (driver_register(&mipsnet_driver)) { | 305 | err = driver_register(&mipsnet_driver); |
306 | if (err) | ||
318 | printk(KERN_ERR "Driver registration failed\n"); | 307 | printk(KERN_ERR "Driver registration failed\n"); |
319 | err = -ENODEV; | ||
320 | goto out; | ||
321 | } | ||
322 | |||
323 | if (!(pldev = kmalloc (sizeof (*pldev), GFP_KERNEL))) { | ||
324 | err = -ENOMEM; | ||
325 | goto out_unregister_driver; | ||
326 | } | ||
327 | |||
328 | memset (pldev, 0, sizeof (*pldev)); | ||
329 | pldev->name = mipsnet_string; | ||
330 | pldev->id = 0; | ||
331 | pldev->dev.release = mipsnet_platform_release; | ||
332 | 308 | ||
333 | if (platform_device_register(pldev)) { | ||
334 | err = -ENODEV; | ||
335 | goto out_free_pldev; | ||
336 | } | ||
337 | |||
338 | if (!pldev->dev.driver) { | ||
339 | /* | ||
340 | * The driver was not bound to this device, there was | ||
341 | * no hardware at this address. Unregister it, as the | ||
342 | * release fuction will take care of freeing the | ||
343 | * allocated structure | ||
344 | */ | ||
345 | platform_device_unregister (pldev); | ||
346 | } | ||
347 | |||
348 | mips_plat_dev = pldev; | ||
349 | |||
350 | return 0; | ||
351 | |||
352 | out_free_pldev: | ||
353 | kfree(pldev); | ||
354 | |||
355 | out_unregister_driver: | ||
356 | driver_unregister(&mipsnet_driver); | ||
357 | out: | ||
358 | return err; | 309 | return err; |
359 | } | 310 | } |
360 | 311 | ||
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index ab15ecd4b3d6..1799eee88db7 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -51,8 +51,8 @@ | |||
51 | #include "mv643xx_eth.h" | 51 | #include "mv643xx_eth.h" |
52 | 52 | ||
53 | /* Static function declarations */ | 53 | /* Static function declarations */ |
54 | static void eth_port_uc_addr_get(struct net_device *dev, | 54 | static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr); |
55 | unsigned char *MacAddr); | 55 | static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr); |
56 | static void eth_port_set_multicast_list(struct net_device *); | 56 | static void eth_port_set_multicast_list(struct net_device *); |
57 | static void mv643xx_eth_port_enable_tx(unsigned int port_num, | 57 | static void mv643xx_eth_port_enable_tx(unsigned int port_num, |
58 | unsigned int queues); | 58 | unsigned int queues); |
@@ -1381,7 +1381,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
1381 | port_num = mp->port_num = pd->port_number; | 1381 | port_num = mp->port_num = pd->port_number; |
1382 | 1382 | ||
1383 | /* set default config values */ | 1383 | /* set default config values */ |
1384 | eth_port_uc_addr_get(dev, dev->dev_addr); | 1384 | eth_port_uc_addr_get(port_num, dev->dev_addr); |
1385 | mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE; | 1385 | mp->rx_ring_size = MV643XX_ETH_PORT_DEFAULT_RECEIVE_QUEUE_SIZE; |
1386 | mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE; | 1386 | mp->tx_ring_size = MV643XX_ETH_PORT_DEFAULT_TRANSMIT_QUEUE_SIZE; |
1387 | 1387 | ||
@@ -1839,26 +1839,9 @@ static void eth_port_start(struct net_device *dev) | |||
1839 | } | 1839 | } |
1840 | 1840 | ||
1841 | /* | 1841 | /* |
1842 | * eth_port_uc_addr_set - This function Set the port Unicast address. | 1842 | * eth_port_uc_addr_set - Write a MAC address into the port's hw registers |
1843 | * | ||
1844 | * DESCRIPTION: | ||
1845 | * This function Set the port Ethernet MAC address. | ||
1846 | * | ||
1847 | * INPUT: | ||
1848 | * unsigned int eth_port_num Port number. | ||
1849 | * char * p_addr Address to be set | ||
1850 | * | ||
1851 | * OUTPUT: | ||
1852 | * Set MAC address low and high registers. also calls | ||
1853 | * eth_port_set_filter_table_entry() to set the unicast | ||
1854 | * table with the proper information. | ||
1855 | * | ||
1856 | * RETURN: | ||
1857 | * N/A. | ||
1858 | * | ||
1859 | */ | 1843 | */ |
1860 | static void eth_port_uc_addr_set(unsigned int eth_port_num, | 1844 | static void eth_port_uc_addr_set(unsigned int port_num, unsigned char *p_addr) |
1861 | unsigned char *p_addr) | ||
1862 | { | 1845 | { |
1863 | unsigned int mac_h; | 1846 | unsigned int mac_h; |
1864 | unsigned int mac_l; | 1847 | unsigned int mac_l; |
@@ -1868,40 +1851,24 @@ static void eth_port_uc_addr_set(unsigned int eth_port_num, | |||
1868 | mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) | | 1851 | mac_h = (p_addr[0] << 24) | (p_addr[1] << 16) | (p_addr[2] << 8) | |
1869 | (p_addr[3] << 0); | 1852 | (p_addr[3] << 0); |
1870 | 1853 | ||
1871 | mv_write(MV643XX_ETH_MAC_ADDR_LOW(eth_port_num), mac_l); | 1854 | mv_write(MV643XX_ETH_MAC_ADDR_LOW(port_num), mac_l); |
1872 | mv_write(MV643XX_ETH_MAC_ADDR_HIGH(eth_port_num), mac_h); | 1855 | mv_write(MV643XX_ETH_MAC_ADDR_HIGH(port_num), mac_h); |
1873 | 1856 | ||
1874 | /* Accept frames of this address */ | 1857 | /* Accept frames with this address */ |
1875 | table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(eth_port_num); | 1858 | table = MV643XX_ETH_DA_FILTER_UNICAST_TABLE_BASE(port_num); |
1876 | eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f); | 1859 | eth_port_set_filter_table_entry(table, p_addr[5] & 0x0f); |
1877 | } | 1860 | } |
1878 | 1861 | ||
1879 | /* | 1862 | /* |
1880 | * eth_port_uc_addr_get - This function retrieves the port Unicast address | 1863 | * eth_port_uc_addr_get - Read the MAC address from the port's hw registers |
1881 | * (MAC address) from the ethernet hw registers. | ||
1882 | * | ||
1883 | * DESCRIPTION: | ||
1884 | * This function retrieves the port Ethernet MAC address. | ||
1885 | * | ||
1886 | * INPUT: | ||
1887 | * unsigned int eth_port_num Port number. | ||
1888 | * char *MacAddr pointer where the MAC address is stored | ||
1889 | * | ||
1890 | * OUTPUT: | ||
1891 | * Copy the MAC address to the location pointed to by MacAddr | ||
1892 | * | ||
1893 | * RETURN: | ||
1894 | * N/A. | ||
1895 | * | ||
1896 | */ | 1864 | */ |
1897 | static void eth_port_uc_addr_get(struct net_device *dev, unsigned char *p_addr) | 1865 | static void eth_port_uc_addr_get(unsigned int port_num, unsigned char *p_addr) |
1898 | { | 1866 | { |
1899 | struct mv643xx_private *mp = netdev_priv(dev); | ||
1900 | unsigned int mac_h; | 1867 | unsigned int mac_h; |
1901 | unsigned int mac_l; | 1868 | unsigned int mac_l; |
1902 | 1869 | ||
1903 | mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(mp->port_num)); | 1870 | mac_h = mv_read(MV643XX_ETH_MAC_ADDR_HIGH(port_num)); |
1904 | mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(mp->port_num)); | 1871 | mac_l = mv_read(MV643XX_ETH_MAC_ADDR_LOW(port_num)); |
1905 | 1872 | ||
1906 | p_addr[0] = (mac_h >> 24) & 0xff; | 1873 | p_addr[0] = (mac_h >> 24) & 0xff; |
1907 | p_addr[1] = (mac_h >> 16) & 0xff; | 1874 | p_addr[1] = (mac_h >> 16) & 0xff; |
diff --git a/drivers/net/mv643xx_eth.h b/drivers/net/mv643xx_eth.h index 7d4e90cf49e8..82f8c0cbfb64 100644 --- a/drivers/net/mv643xx_eth.h +++ b/drivers/net/mv643xx_eth.h | |||
@@ -346,10 +346,6 @@ static void eth_port_init(struct mv643xx_private *mp); | |||
346 | static void eth_port_reset(unsigned int eth_port_num); | 346 | static void eth_port_reset(unsigned int eth_port_num); |
347 | static void eth_port_start(struct net_device *dev); | 347 | static void eth_port_start(struct net_device *dev); |
348 | 348 | ||
349 | /* Port MAC address routines */ | ||
350 | static void eth_port_uc_addr_set(unsigned int eth_port_num, | ||
351 | unsigned char *p_addr); | ||
352 | |||
353 | /* PHY and MIB routines */ | 349 | /* PHY and MIB routines */ |
354 | static void ethernet_phy_reset(unsigned int eth_port_num); | 350 | static void ethernet_phy_reset(unsigned int eth_port_num); |
355 | 351 | ||
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index dd8ce35332fe..ad6688eab265 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h | |||
@@ -64,9 +64,9 @@ | |||
64 | #include "netxen_nic_hw.h" | 64 | #include "netxen_nic_hw.h" |
65 | 65 | ||
66 | #define _NETXEN_NIC_LINUX_MAJOR 3 | 66 | #define _NETXEN_NIC_LINUX_MAJOR 3 |
67 | #define _NETXEN_NIC_LINUX_MINOR 3 | 67 | #define _NETXEN_NIC_LINUX_MINOR 4 |
68 | #define _NETXEN_NIC_LINUX_SUBVERSION 3 | 68 | #define _NETXEN_NIC_LINUX_SUBVERSION 2 |
69 | #define NETXEN_NIC_LINUX_VERSIONID "3.3.3" | 69 | #define NETXEN_NIC_LINUX_VERSIONID "3.4.2" |
70 | 70 | ||
71 | #define NUM_FLASH_SECTORS (64) | 71 | #define NUM_FLASH_SECTORS (64) |
72 | #define FLASH_SECTOR_SIZE (64 * 1024) | 72 | #define FLASH_SECTOR_SIZE (64 * 1024) |
@@ -131,8 +131,8 @@ extern struct workqueue_struct *netxen_workq; | |||
131 | #define FIRST_PAGE_GROUP_START 0 | 131 | #define FIRST_PAGE_GROUP_START 0 |
132 | #define FIRST_PAGE_GROUP_END 0x100000 | 132 | #define FIRST_PAGE_GROUP_END 0x100000 |
133 | 133 | ||
134 | #define SECOND_PAGE_GROUP_START 0x4000000 | 134 | #define SECOND_PAGE_GROUP_START 0x6000000 |
135 | #define SECOND_PAGE_GROUP_END 0x66BC000 | 135 | #define SECOND_PAGE_GROUP_END 0x68BC000 |
136 | 136 | ||
137 | #define THIRD_PAGE_GROUP_START 0x70E4000 | 137 | #define THIRD_PAGE_GROUP_START 0x70E4000 |
138 | #define THIRD_PAGE_GROUP_END 0x8000000 | 138 | #define THIRD_PAGE_GROUP_END 0x8000000 |
@@ -205,6 +205,8 @@ enum { | |||
205 | 205 | ||
206 | #define MAX_CMD_DESCRIPTORS 1024 | 206 | #define MAX_CMD_DESCRIPTORS 1024 |
207 | #define MAX_RCV_DESCRIPTORS 16384 | 207 | #define MAX_RCV_DESCRIPTORS 16384 |
208 | #define MAX_CMD_DESCRIPTORS_HOST (MAX_CMD_DESCRIPTORS / 4) | ||
209 | #define MAX_RCV_DESCRIPTORS_1G (MAX_RCV_DESCRIPTORS / 4) | ||
208 | #define MAX_JUMBO_RCV_DESCRIPTORS 1024 | 210 | #define MAX_JUMBO_RCV_DESCRIPTORS 1024 |
209 | #define MAX_LRO_RCV_DESCRIPTORS 64 | 211 | #define MAX_LRO_RCV_DESCRIPTORS 64 |
210 | #define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS | 212 | #define MAX_RCVSTATUS_DESCRIPTORS MAX_RCV_DESCRIPTORS |
@@ -230,7 +232,9 @@ enum { | |||
230 | (((index) + (count)) & ((length) - 1)) | 232 | (((index) + (count)) & ((length) - 1)) |
231 | 233 | ||
232 | #define MPORT_SINGLE_FUNCTION_MODE 0x1111 | 234 | #define MPORT_SINGLE_FUNCTION_MODE 0x1111 |
235 | #define MPORT_MULTI_FUNCTION_MODE 0x2222 | ||
233 | 236 | ||
237 | #include "netxen_nic_phan_reg.h" | ||
234 | extern unsigned long long netxen_dma_mask; | 238 | extern unsigned long long netxen_dma_mask; |
235 | extern unsigned long last_schedule_time; | 239 | extern unsigned long last_schedule_time; |
236 | 240 | ||
@@ -300,6 +304,8 @@ struct netxen_ring_ctx { | |||
300 | 304 | ||
301 | #define netxen_set_cmd_desc_port(cmd_desc, var) \ | 305 | #define netxen_set_cmd_desc_port(cmd_desc, var) \ |
302 | ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) | 306 | ((cmd_desc)->port_ctxid |= ((var) & 0x0F)) |
307 | #define netxen_set_cmd_desc_ctxid(cmd_desc, var) \ | ||
308 | ((cmd_desc)->port_ctxid |= ((var) & 0xF0)) | ||
303 | 309 | ||
304 | #define netxen_set_cmd_desc_flags(cmd_desc, val) \ | 310 | #define netxen_set_cmd_desc_flags(cmd_desc, val) \ |
305 | ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \ | 311 | ((cmd_desc)->flags_opcode &= ~cpu_to_le16(0x7f), \ |
@@ -442,7 +448,7 @@ struct status_desc { | |||
442 | /* Bit pattern: 0-6 lro_count indicates frag sequence, | 448 | /* Bit pattern: 0-6 lro_count indicates frag sequence, |
443 | 7 last_frag indicates last frag */ | 449 | 7 last_frag indicates last frag */ |
444 | u8 lro; | 450 | u8 lro; |
445 | } __attribute__ ((aligned(8))); | 451 | } __attribute__ ((aligned(16))); |
446 | 452 | ||
447 | enum { | 453 | enum { |
448 | NETXEN_RCV_PEG_0 = 0, | 454 | NETXEN_RCV_PEG_0 = 0, |
@@ -703,10 +709,8 @@ extern char netxen_nic_driver_name[]; | |||
703 | #else | 709 | #else |
704 | #define DPRINTK(klevel, fmt, args...) do { \ | 710 | #define DPRINTK(klevel, fmt, args...) do { \ |
705 | printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\ | 711 | printk(KERN_##klevel PFX "%s: %s: " fmt, __FUNCTION__,\ |
706 | (adapter != NULL && \ | 712 | (adapter != NULL && adapter->netdev != NULL) ? \ |
707 | adapter->port[0] != NULL && \ | 713 | adapter->netdev->name : NULL, \ |
708 | adapter->port[0]->netdev != NULL) ? \ | ||
709 | adapter->port[0]->netdev->name : NULL, \ | ||
710 | ## args); } while(0) | 714 | ## args); } while(0) |
711 | #endif | 715 | #endif |
712 | 716 | ||
@@ -722,6 +726,18 @@ struct netxen_skb_frag { | |||
722 | u32 length; | 726 | u32 length; |
723 | }; | 727 | }; |
724 | 728 | ||
729 | #define _netxen_set_bits(config_word, start, bits, val) {\ | ||
730 | unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start));\ | ||
731 | unsigned long long __tvalue = (val); \ | ||
732 | (config_word) &= ~__tmask; \ | ||
733 | (config_word) |= (((__tvalue) << (start)) & __tmask); \ | ||
734 | } | ||
735 | |||
736 | #define _netxen_clear_bits(config_word, start, bits) {\ | ||
737 | unsigned long long __tmask = (((1ULL << (bits)) - 1) << (start)); \ | ||
738 | (config_word) &= ~__tmask; \ | ||
739 | } | ||
740 | |||
725 | /* Following defines are for the state of the buffers */ | 741 | /* Following defines are for the state of the buffers */ |
726 | #define NETXEN_BUFFER_FREE 0 | 742 | #define NETXEN_BUFFER_FREE 0 |
727 | #define NETXEN_BUFFER_BUSY 1 | 743 | #define NETXEN_BUFFER_BUSY 1 |
@@ -766,6 +782,8 @@ struct netxen_hardware_context { | |||
766 | void __iomem *pci_base0; | 782 | void __iomem *pci_base0; |
767 | void __iomem *pci_base1; | 783 | void __iomem *pci_base1; |
768 | void __iomem *pci_base2; | 784 | void __iomem *pci_base2; |
785 | unsigned long first_page_group_end; | ||
786 | unsigned long first_page_group_start; | ||
769 | void __iomem *db_base; | 787 | void __iomem *db_base; |
770 | unsigned long db_len; | 788 | unsigned long db_len; |
771 | 789 | ||
@@ -780,6 +798,7 @@ struct netxen_hardware_context { | |||
780 | struct pci_dev *cmd_desc_pdev; | 798 | struct pci_dev *cmd_desc_pdev; |
781 | dma_addr_t cmd_desc_phys_addr; | 799 | dma_addr_t cmd_desc_phys_addr; |
782 | struct netxen_adapter *adapter; | 800 | struct netxen_adapter *adapter; |
801 | int pci_func; | ||
783 | }; | 802 | }; |
784 | 803 | ||
785 | #define RCV_RING_LRO RCV_DESC_LRO | 804 | #define RCV_RING_LRO RCV_DESC_LRO |
@@ -788,17 +807,27 @@ struct netxen_hardware_context { | |||
788 | #define ETHERNET_FCS_SIZE 4 | 807 | #define ETHERNET_FCS_SIZE 4 |
789 | 808 | ||
790 | struct netxen_adapter_stats { | 809 | struct netxen_adapter_stats { |
791 | u64 ints; | 810 | u64 rcvdbadskb; |
792 | u64 hostints; | 811 | u64 xmitcalled; |
793 | u64 otherints; | 812 | u64 xmitedframes; |
794 | u64 process_rcv; | 813 | u64 xmitfinished; |
795 | u64 process_xmit; | 814 | u64 badskblen; |
796 | u64 noxmitdone; | 815 | u64 nocmddescriptor; |
797 | u64 xmitcsummed; | 816 | u64 polled; |
798 | u64 post_called; | 817 | u64 uphappy; |
799 | u64 posted; | 818 | u64 updropped; |
800 | u64 lastposted; | 819 | u64 uplcong; |
801 | u64 goodskbposts; | 820 | u64 uphcong; |
821 | u64 upmcong; | ||
822 | u64 updunno; | ||
823 | u64 skbfreed; | ||
824 | u64 txdropped; | ||
825 | u64 txnullskb; | ||
826 | u64 csummed; | ||
827 | u64 no_rcv; | ||
828 | u64 rxbytes; | ||
829 | u64 txbytes; | ||
830 | u64 ints; | ||
802 | }; | 831 | }; |
803 | 832 | ||
804 | /* | 833 | /* |
@@ -846,13 +875,20 @@ struct netxen_dummy_dma { | |||
846 | 875 | ||
847 | struct netxen_adapter { | 876 | struct netxen_adapter { |
848 | struct netxen_hardware_context ahw; | 877 | struct netxen_hardware_context ahw; |
849 | int port_count; /* Number of configured ports */ | 878 | |
850 | int active_ports; /* Number of open ports */ | 879 | struct netxen_adapter *master; |
851 | struct netxen_port *port[NETXEN_MAX_PORTS]; /* ptr to each port */ | 880 | struct net_device *netdev; |
881 | struct pci_dev *pdev; | ||
882 | struct net_device_stats net_stats; | ||
883 | unsigned char mac_addr[ETH_ALEN]; | ||
884 | int mtu; | ||
885 | int portnum; | ||
886 | |||
852 | spinlock_t tx_lock; | 887 | spinlock_t tx_lock; |
853 | spinlock_t lock; | 888 | spinlock_t lock; |
854 | struct work_struct watchdog_task; | 889 | struct work_struct watchdog_task; |
855 | struct timer_list watchdog_timer; | 890 | struct timer_list watchdog_timer; |
891 | struct work_struct tx_timeout_task; | ||
856 | 892 | ||
857 | u32 curr_window; | 893 | u32 curr_window; |
858 | 894 | ||
@@ -875,6 +911,15 @@ struct netxen_adapter { | |||
875 | u32 temp; | 911 | u32 temp; |
876 | 912 | ||
877 | struct netxen_adapter_stats stats; | 913 | struct netxen_adapter_stats stats; |
914 | |||
915 | u16 portno; | ||
916 | u16 link_speed; | ||
917 | u16 link_duplex; | ||
918 | u16 state; | ||
919 | u16 link_autoneg; | ||
920 | int rcsum; | ||
921 | int status; | ||
922 | spinlock_t stats_lock; | ||
878 | 923 | ||
879 | struct netxen_cmd_buffer *cmd_buf_arr; /* Command buffers for xmit */ | 924 | struct netxen_cmd_buffer *cmd_buf_arr; /* Command buffers for xmit */ |
880 | 925 | ||
@@ -891,65 +936,23 @@ struct netxen_adapter { | |||
891 | struct netxen_ring_ctx *ctx_desc; | 936 | struct netxen_ring_ctx *ctx_desc; |
892 | struct pci_dev *ctx_desc_pdev; | 937 | struct pci_dev *ctx_desc_pdev; |
893 | dma_addr_t ctx_desc_phys_addr; | 938 | dma_addr_t ctx_desc_phys_addr; |
894 | int (*enable_phy_interrupts) (struct netxen_adapter *, int); | 939 | int (*enable_phy_interrupts) (struct netxen_adapter *); |
895 | int (*disable_phy_interrupts) (struct netxen_adapter *, int); | 940 | int (*disable_phy_interrupts) (struct netxen_adapter *); |
896 | void (*handle_phy_intr) (struct netxen_adapter *); | 941 | void (*handle_phy_intr) (struct netxen_adapter *); |
897 | int (*macaddr_set) (struct netxen_port *, netxen_ethernet_macaddr_t); | 942 | int (*macaddr_set) (struct netxen_adapter *, netxen_ethernet_macaddr_t); |
898 | int (*set_mtu) (struct netxen_port *, int); | 943 | int (*set_mtu) (struct netxen_adapter *, int); |
899 | int (*set_promisc) (struct netxen_adapter *, int, | 944 | int (*set_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t); |
900 | netxen_niu_prom_mode_t); | 945 | int (*unset_promisc) (struct netxen_adapter *, netxen_niu_prom_mode_t); |
901 | int (*unset_promisc) (struct netxen_adapter *, int, | 946 | int (*phy_read) (struct netxen_adapter *, long reg, u32 *); |
902 | netxen_niu_prom_mode_t); | 947 | int (*phy_write) (struct netxen_adapter *, long reg, u32 val); |
903 | int (*phy_read) (struct netxen_adapter *, long phy, long reg, u32 *); | ||
904 | int (*phy_write) (struct netxen_adapter *, long phy, long reg, u32 val); | ||
905 | int (*init_port) (struct netxen_adapter *, int); | 948 | int (*init_port) (struct netxen_adapter *, int); |
906 | void (*init_niu) (struct netxen_adapter *); | 949 | void (*init_niu) (struct netxen_adapter *); |
907 | int (*stop_port) (struct netxen_adapter *, int); | 950 | int (*stop_port) (struct netxen_adapter *); |
908 | }; /* netxen_adapter structure */ | 951 | }; /* netxen_adapter structure */ |
909 | 952 | ||
910 | /* Max number of xmit producer threads that can run simultaneously */ | 953 | /* Max number of xmit producer threads that can run simultaneously */ |
911 | #define MAX_XMIT_PRODUCERS 16 | 954 | #define MAX_XMIT_PRODUCERS 16 |
912 | 955 | ||
913 | struct netxen_port_stats { | ||
914 | u64 rcvdbadskb; | ||
915 | u64 xmitcalled; | ||
916 | u64 xmitedframes; | ||
917 | u64 xmitfinished; | ||
918 | u64 badskblen; | ||
919 | u64 nocmddescriptor; | ||
920 | u64 polled; | ||
921 | u64 uphappy; | ||
922 | u64 updropped; | ||
923 | u64 uplcong; | ||
924 | u64 uphcong; | ||
925 | u64 upmcong; | ||
926 | u64 updunno; | ||
927 | u64 skbfreed; | ||
928 | u64 txdropped; | ||
929 | u64 txnullskb; | ||
930 | u64 csummed; | ||
931 | u64 no_rcv; | ||
932 | u64 rxbytes; | ||
933 | u64 txbytes; | ||
934 | }; | ||
935 | |||
936 | struct netxen_port { | ||
937 | struct netxen_adapter *adapter; | ||
938 | |||
939 | u16 portnum; /* GBE port number */ | ||
940 | u16 link_speed; | ||
941 | u16 link_duplex; | ||
942 | u16 link_autoneg; | ||
943 | |||
944 | int flags; | ||
945 | |||
946 | struct net_device *netdev; | ||
947 | struct pci_dev *pdev; | ||
948 | struct net_device_stats net_stats; | ||
949 | struct netxen_port_stats stats; | ||
950 | struct work_struct tx_timeout_task; | ||
951 | }; | ||
952 | |||
953 | #define PCI_OFFSET_FIRST_RANGE(adapter, off) \ | 956 | #define PCI_OFFSET_FIRST_RANGE(adapter, off) \ |
954 | ((adapter)->ahw.pci_base0 + (off)) | 957 | ((adapter)->ahw.pci_base0 + (off)) |
955 | #define PCI_OFFSET_SECOND_RANGE(adapter, off) \ | 958 | #define PCI_OFFSET_SECOND_RANGE(adapter, off) \ |
@@ -987,32 +990,26 @@ static inline void __iomem *pci_base(struct netxen_adapter *adapter, | |||
987 | return NULL; | 990 | return NULL; |
988 | } | 991 | } |
989 | 992 | ||
990 | int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter, | 993 | int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter); |
991 | int port); | 994 | int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter); |
992 | int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, | 995 | int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter); |
993 | int port); | 996 | int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter); |
994 | int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter, | 997 | int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter); |
995 | int port); | 998 | int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter); |
996 | int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter, | ||
997 | int port); | ||
998 | int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter, | ||
999 | int port); | ||
1000 | int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter, | ||
1001 | int port); | ||
1002 | void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter); | 999 | void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter); |
1003 | void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter); | 1000 | void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter); |
1004 | void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port, | 1001 | void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, int port, |
1005 | long enable); | 1002 | long enable); |
1006 | void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port, | 1003 | void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, int port, |
1007 | long enable); | 1004 | long enable); |
1008 | int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, long reg, | 1005 | int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, |
1009 | __u32 * readval); | 1006 | __u32 * readval); |
1010 | int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long phy, | 1007 | int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, |
1011 | long reg, __u32 val); | 1008 | long reg, __u32 val); |
1012 | 1009 | ||
1013 | /* Functions available from netxen_nic_hw.c */ | 1010 | /* Functions available from netxen_nic_hw.c */ |
1014 | int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu); | 1011 | int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu); |
1015 | int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu); | 1012 | int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu); |
1016 | void netxen_nic_init_niu_gb(struct netxen_adapter *adapter); | 1013 | void netxen_nic_init_niu_gb(struct netxen_adapter *adapter); |
1017 | void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw); | 1014 | void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw); |
1018 | void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val); | 1015 | void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val); |
@@ -1027,6 +1024,7 @@ int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data, | |||
1027 | int len); | 1024 | int len); |
1028 | void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, | 1025 | void netxen_crb_writelit_adapter(struct netxen_adapter *adapter, |
1029 | unsigned long off, int data); | 1026 | unsigned long off, int data); |
1027 | int netxen_nic_erase_pxe(struct netxen_adapter *adapter); | ||
1030 | 1028 | ||
1031 | /* Functions from netxen_nic_init.c */ | 1029 | /* Functions from netxen_nic_init.c */ |
1032 | void netxen_free_adapter_offload(struct netxen_adapter *adapter); | 1030 | void netxen_free_adapter_offload(struct netxen_adapter *adapter); |
@@ -1051,11 +1049,8 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr); | |||
1051 | 1049 | ||
1052 | /* Functions from netxen_nic_isr.c */ | 1050 | /* Functions from netxen_nic_isr.c */ |
1053 | void netxen_nic_isr_other(struct netxen_adapter *adapter); | 1051 | void netxen_nic_isr_other(struct netxen_adapter *adapter); |
1054 | void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 port, | 1052 | void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link); |
1055 | u32 link); | 1053 | void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable); |
1056 | void netxen_handle_port_int(struct netxen_adapter *adapter, u32 port, | ||
1057 | u32 enable); | ||
1058 | void netxen_nic_stop_all_ports(struct netxen_adapter *adapter); | ||
1059 | void netxen_initialize_adapter_sw(struct netxen_adapter *adapter); | 1054 | void netxen_initialize_adapter_sw(struct netxen_adapter *adapter); |
1060 | void netxen_initialize_adapter_hw(struct netxen_adapter *adapter); | 1055 | void netxen_initialize_adapter_hw(struct netxen_adapter *adapter); |
1061 | void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr, | 1056 | void *netxen_alloc(struct pci_dev *pdev, size_t sz, dma_addr_t * ptr, |
@@ -1110,6 +1105,7 @@ static inline void netxen_nic_enable_int(struct netxen_adapter *adapter) | |||
1110 | 1105 | ||
1111 | if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { | 1106 | if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { |
1112 | mask = 0xbff; | 1107 | mask = 0xbff; |
1108 | writel(0X0, NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); | ||
1113 | writel(mask, PCI_OFFSET_SECOND_RANGE(adapter, | 1109 | writel(mask, PCI_OFFSET_SECOND_RANGE(adapter, |
1114 | ISR_INT_TARGET_MASK)); | 1110 | ISR_INT_TARGET_MASK)); |
1115 | } | 1111 | } |
@@ -1174,4 +1170,5 @@ extern int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, | |||
1174 | 1170 | ||
1175 | extern struct ethtool_ops netxen_nic_ethtool_ops; | 1171 | extern struct ethtool_ops netxen_nic_ethtool_ops; |
1176 | 1172 | ||
1173 | extern int physical_port[]; /* physical port # from virtual port.*/ | ||
1177 | #endif /* __NETXEN_NIC_H_ */ | 1174 | #endif /* __NETXEN_NIC_H_ */ |
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index ee1b5a24cbe7..16fabb377488 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c | |||
@@ -40,8 +40,8 @@ | |||
40 | #include <linux/ethtool.h> | 40 | #include <linux/ethtool.h> |
41 | #include <linux/version.h> | 41 | #include <linux/version.h> |
42 | 42 | ||
43 | #include "netxen_nic_hw.h" | ||
44 | #include "netxen_nic.h" | 43 | #include "netxen_nic.h" |
44 | #include "netxen_nic_hw.h" | ||
45 | #include "netxen_nic_phan_reg.h" | 45 | #include "netxen_nic_phan_reg.h" |
46 | 46 | ||
47 | struct netxen_nic_stats { | 47 | struct netxen_nic_stats { |
@@ -50,8 +50,8 @@ struct netxen_nic_stats { | |||
50 | int stat_offset; | 50 | int stat_offset; |
51 | }; | 51 | }; |
52 | 52 | ||
53 | #define NETXEN_NIC_STAT(m) sizeof(((struct netxen_port *)0)->m), \ | 53 | #define NETXEN_NIC_STAT(m) sizeof(((struct netxen_adapter *)0)->m), \ |
54 | offsetof(struct netxen_port, m) | 54 | offsetof(struct netxen_adapter, m) |
55 | 55 | ||
56 | #define NETXEN_NIC_PORT_WINDOW 0x10000 | 56 | #define NETXEN_NIC_PORT_WINDOW 0x10000 |
57 | #define NETXEN_NIC_INVALID_DATA 0xDEADBEEF | 57 | #define NETXEN_NIC_INVALID_DATA 0xDEADBEEF |
@@ -100,8 +100,7 @@ static int netxen_nic_get_eeprom_len(struct net_device *dev) | |||
100 | static void | 100 | static void |
101 | netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) | 101 | netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) |
102 | { | 102 | { |
103 | struct netxen_port *port = netdev_priv(dev); | 103 | struct netxen_adapter *adapter = netdev_priv(dev); |
104 | struct netxen_adapter *adapter = port->adapter; | ||
105 | u32 fw_major = 0; | 104 | u32 fw_major = 0; |
106 | u32 fw_minor = 0; | 105 | u32 fw_minor = 0; |
107 | u32 fw_build = 0; | 106 | u32 fw_build = 0; |
@@ -115,7 +114,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) | |||
115 | fw_build = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB)); | 114 | fw_build = readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB)); |
116 | sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); | 115 | sprintf(drvinfo->fw_version, "%d.%d.%d", fw_major, fw_minor, fw_build); |
117 | 116 | ||
118 | strncpy(drvinfo->bus_info, pci_name(port->pdev), 32); | 117 | strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); |
119 | drvinfo->n_stats = NETXEN_NIC_STATS_LEN; | 118 | drvinfo->n_stats = NETXEN_NIC_STATS_LEN; |
120 | drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN; | 119 | drvinfo->testinfo_len = NETXEN_NIC_TEST_LEN; |
121 | drvinfo->regdump_len = NETXEN_NIC_REGS_LEN; | 120 | drvinfo->regdump_len = NETXEN_NIC_REGS_LEN; |
@@ -125,8 +124,7 @@ netxen_nic_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) | |||
125 | static int | 124 | static int |
126 | netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | 125 | netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) |
127 | { | 126 | { |
128 | struct netxen_port *port = netdev_priv(dev); | 127 | struct netxen_adapter *adapter = netdev_priv(dev); |
129 | struct netxen_adapter *adapter = port->adapter; | ||
130 | struct netxen_board_info *boardinfo = &adapter->ahw.boardcfg; | 128 | struct netxen_board_info *boardinfo = &adapter->ahw.boardcfg; |
131 | 129 | ||
132 | /* read which mode */ | 130 | /* read which mode */ |
@@ -146,8 +144,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
146 | ecmd->port = PORT_TP; | 144 | ecmd->port = PORT_TP; |
147 | 145 | ||
148 | if (netif_running(dev)) { | 146 | if (netif_running(dev)) { |
149 | ecmd->speed = port->link_speed; | 147 | ecmd->speed = adapter->link_speed; |
150 | ecmd->duplex = port->link_duplex; | 148 | ecmd->duplex = adapter->link_duplex; |
151 | } else | 149 | } else |
152 | return -EIO; /* link absent */ | 150 | return -EIO; /* link absent */ |
153 | } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { | 151 | } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { |
@@ -165,7 +163,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
165 | } else | 163 | } else |
166 | return -EIO; | 164 | return -EIO; |
167 | 165 | ||
168 | ecmd->phy_address = port->portnum; | 166 | ecmd->phy_address = adapter->portnum; |
169 | ecmd->transceiver = XCVR_EXTERNAL; | 167 | ecmd->transceiver = XCVR_EXTERNAL; |
170 | 168 | ||
171 | switch ((netxen_brdtype_t) boardinfo->board_type) { | 169 | switch ((netxen_brdtype_t) boardinfo->board_type) { |
@@ -179,7 +177,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
179 | ecmd->port = PORT_TP; | 177 | ecmd->port = PORT_TP; |
180 | ecmd->autoneg = (boardinfo->board_type == | 178 | ecmd->autoneg = (boardinfo->board_type == |
181 | NETXEN_BRDTYPE_P2_SB31_10G_CX4) ? | 179 | NETXEN_BRDTYPE_P2_SB31_10G_CX4) ? |
182 | (AUTONEG_DISABLE) : (port->link_autoneg); | 180 | (AUTONEG_DISABLE) : (adapter->link_autoneg); |
183 | break; | 181 | break; |
184 | case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ: | 182 | case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ: |
185 | case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ: | 183 | case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ: |
@@ -206,23 +204,22 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
206 | static int | 204 | static int |
207 | netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | 205 | netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) |
208 | { | 206 | { |
209 | struct netxen_port *port = netdev_priv(dev); | 207 | struct netxen_adapter *adapter = netdev_priv(dev); |
210 | struct netxen_adapter *adapter = port->adapter; | ||
211 | __u32 status; | 208 | __u32 status; |
212 | 209 | ||
213 | /* read which mode */ | 210 | /* read which mode */ |
214 | if (adapter->ahw.board_type == NETXEN_NIC_GBE) { | 211 | if (adapter->ahw.board_type == NETXEN_NIC_GBE) { |
215 | /* autonegotiation */ | 212 | /* autonegotiation */ |
216 | if (adapter->phy_write | 213 | if (adapter->phy_write |
217 | && adapter->phy_write(adapter, port->portnum, | 214 | && adapter->phy_write(adapter, |
218 | NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, | 215 | NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, |
219 | ecmd->autoneg) != 0) | 216 | ecmd->autoneg) != 0) |
220 | return -EIO; | 217 | return -EIO; |
221 | else | 218 | else |
222 | port->link_autoneg = ecmd->autoneg; | 219 | adapter->link_autoneg = ecmd->autoneg; |
223 | 220 | ||
224 | if (adapter->phy_read | 221 | if (adapter->phy_read |
225 | && adapter->phy_read(adapter, port->portnum, | 222 | && adapter->phy_read(adapter, |
226 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, | 223 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
227 | &status) != 0) | 224 | &status) != 0) |
228 | return -EIO; | 225 | return -EIO; |
@@ -245,13 +242,13 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) | |||
245 | if (ecmd->duplex == DUPLEX_FULL) | 242 | if (ecmd->duplex == DUPLEX_FULL) |
246 | netxen_set_phy_duplex(status); | 243 | netxen_set_phy_duplex(status); |
247 | if (adapter->phy_write | 244 | if (adapter->phy_write |
248 | && adapter->phy_write(adapter, port->portnum, | 245 | && adapter->phy_write(adapter, |
249 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, | 246 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
250 | *((int *)&status)) != 0) | 247 | *((int *)&status)) != 0) |
251 | return -EIO; | 248 | return -EIO; |
252 | else { | 249 | else { |
253 | port->link_speed = ecmd->speed; | 250 | adapter->link_speed = ecmd->speed; |
254 | port->link_duplex = ecmd->duplex; | 251 | adapter->link_duplex = ecmd->duplex; |
255 | } | 252 | } |
256 | } else | 253 | } else |
257 | return -EOPNOTSUPP; | 254 | return -EOPNOTSUPP; |
@@ -360,15 +357,14 @@ static struct netxen_niu_regs niu_registers[] = { | |||
360 | static void | 357 | static void |
361 | netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) | 358 | netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) |
362 | { | 359 | { |
363 | struct netxen_port *port = netdev_priv(dev); | 360 | struct netxen_adapter *adapter = netdev_priv(dev); |
364 | struct netxen_adapter *adapter = port->adapter; | ||
365 | __u32 mode, *regs_buff = p; | 361 | __u32 mode, *regs_buff = p; |
366 | void __iomem *addr; | 362 | void __iomem *addr; |
367 | int i, window; | 363 | int i, window; |
368 | 364 | ||
369 | memset(p, 0, NETXEN_NIC_REGS_LEN); | 365 | memset(p, 0, NETXEN_NIC_REGS_LEN); |
370 | regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | | 366 | regs->version = (1 << 24) | (adapter->ahw.revision_id << 16) | |
371 | (port->pdev)->device; | 367 | (adapter->pdev)->device; |
372 | /* which mode */ | 368 | /* which mode */ |
373 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_MODE, ®s_buff[0]); | 369 | NETXEN_NIC_LOCKED_READ_REG(NETXEN_NIU_MODE, ®s_buff[0]); |
374 | mode = regs_buff[0]; | 370 | mode = regs_buff[0]; |
@@ -383,7 +379,8 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) | |||
383 | for (i = 3; niu_registers[mode].reg[i - 3] != -1; i++) { | 379 | for (i = 3; niu_registers[mode].reg[i - 3] != -1; i++) { |
384 | /* GB: port specific registers */ | 380 | /* GB: port specific registers */ |
385 | if (mode == 0 && i >= 19) | 381 | if (mode == 0 && i >= 19) |
386 | window = port->portnum * NETXEN_NIC_PORT_WINDOW; | 382 | window = physical_port[adapter->portnum] * |
383 | NETXEN_NIC_PORT_WINDOW; | ||
387 | 384 | ||
388 | NETXEN_NIC_LOCKED_READ_REG(niu_registers[mode]. | 385 | NETXEN_NIC_LOCKED_READ_REG(niu_registers[mode]. |
389 | reg[i - 3] + window, | 386 | reg[i - 3] + window, |
@@ -395,15 +392,14 @@ netxen_nic_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *p) | |||
395 | 392 | ||
396 | static u32 netxen_nic_test_link(struct net_device *dev) | 393 | static u32 netxen_nic_test_link(struct net_device *dev) |
397 | { | 394 | { |
398 | struct netxen_port *port = netdev_priv(dev); | 395 | struct netxen_adapter *adapter = netdev_priv(dev); |
399 | struct netxen_adapter *adapter = port->adapter; | ||
400 | __u32 status; | 396 | __u32 status; |
401 | int val; | 397 | int val; |
402 | 398 | ||
403 | /* read which mode */ | 399 | /* read which mode */ |
404 | if (adapter->ahw.board_type == NETXEN_NIC_GBE) { | 400 | if (adapter->ahw.board_type == NETXEN_NIC_GBE) { |
405 | if (adapter->phy_read | 401 | if (adapter->phy_read |
406 | && adapter->phy_read(adapter, port->portnum, | 402 | && adapter->phy_read(adapter, |
407 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, | 403 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
408 | &status) != 0) | 404 | &status) != 0) |
409 | return -EIO; | 405 | return -EIO; |
@@ -422,15 +418,15 @@ static int | |||
422 | netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | 418 | netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, |
423 | u8 * bytes) | 419 | u8 * bytes) |
424 | { | 420 | { |
425 | struct netxen_port *port = netdev_priv(dev); | 421 | struct netxen_adapter *adapter = netdev_priv(dev); |
426 | struct netxen_adapter *adapter = port->adapter; | ||
427 | int offset; | 422 | int offset; |
428 | int ret; | 423 | int ret; |
429 | 424 | ||
430 | if (eeprom->len == 0) | 425 | if (eeprom->len == 0) |
431 | return -EINVAL; | 426 | return -EINVAL; |
432 | 427 | ||
433 | eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16); | 428 | eeprom->magic = (adapter->pdev)->vendor | |
429 | ((adapter->pdev)->device << 16); | ||
434 | offset = eeprom->offset; | 430 | offset = eeprom->offset; |
435 | 431 | ||
436 | ret = netxen_rom_fast_read_words(adapter, offset, bytes, | 432 | ret = netxen_rom_fast_read_words(adapter, offset, bytes, |
@@ -445,8 +441,7 @@ static int | |||
445 | netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | 441 | netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, |
446 | u8 * bytes) | 442 | u8 * bytes) |
447 | { | 443 | { |
448 | struct netxen_port *port = netdev_priv(dev); | 444 | struct netxen_adapter *adapter = netdev_priv(dev); |
449 | struct netxen_adapter *adapter = port->adapter; | ||
450 | int offset = eeprom->offset; | 445 | int offset = eeprom->offset; |
451 | static int flash_start; | 446 | static int flash_start; |
452 | static int ready_to_flash; | 447 | static int ready_to_flash; |
@@ -516,8 +511,7 @@ netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, | |||
516 | static void | 511 | static void |
517 | netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) | 512 | netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring) |
518 | { | 513 | { |
519 | struct netxen_port *port = netdev_priv(dev); | 514 | struct netxen_adapter *adapter = netdev_priv(dev); |
520 | struct netxen_adapter *adapter = port->adapter; | ||
521 | int i; | 515 | int i; |
522 | 516 | ||
523 | ring->rx_pending = 0; | 517 | ring->rx_pending = 0; |
@@ -541,19 +535,45 @@ static void | |||
541 | netxen_nic_get_pauseparam(struct net_device *dev, | 535 | netxen_nic_get_pauseparam(struct net_device *dev, |
542 | struct ethtool_pauseparam *pause) | 536 | struct ethtool_pauseparam *pause) |
543 | { | 537 | { |
544 | struct netxen_port *port = netdev_priv(dev); | 538 | struct netxen_adapter *adapter = netdev_priv(dev); |
545 | struct netxen_adapter *adapter = port->adapter; | ||
546 | __u32 val; | 539 | __u32 val; |
540 | int port = physical_port[adapter->portnum]; | ||
547 | 541 | ||
548 | if (adapter->ahw.board_type == NETXEN_NIC_GBE) { | 542 | if (adapter->ahw.board_type == NETXEN_NIC_GBE) { |
543 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) | ||
544 | return; | ||
549 | /* get flow control settings */ | 545 | /* get flow control settings */ |
550 | netxen_nic_read_w0(adapter, | 546 | netxen_nic_read_w0(adapter,NETXEN_NIU_GB_MAC_CONFIG_0(port), |
551 | NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum), | 547 | &val); |
552 | &val); | ||
553 | pause->rx_pause = netxen_gb_get_rx_flowctl(val); | 548 | pause->rx_pause = netxen_gb_get_rx_flowctl(val); |
554 | pause->tx_pause = netxen_gb_get_tx_flowctl(val); | 549 | netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val); |
555 | /* get autoneg settings */ | 550 | switch (port) { |
556 | pause->autoneg = port->link_autoneg; | 551 | case 0: |
552 | pause->tx_pause = !(netxen_gb_get_gb0_mask(val)); | ||
553 | break; | ||
554 | case 1: | ||
555 | pause->tx_pause = !(netxen_gb_get_gb1_mask(val)); | ||
556 | break; | ||
557 | case 2: | ||
558 | pause->tx_pause = !(netxen_gb_get_gb2_mask(val)); | ||
559 | break; | ||
560 | case 3: | ||
561 | default: | ||
562 | pause->tx_pause = !(netxen_gb_get_gb3_mask(val)); | ||
563 | break; | ||
564 | } | ||
565 | } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { | ||
566 | if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) | ||
567 | return; | ||
568 | pause->rx_pause = 1; | ||
569 | netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val); | ||
570 | if (port == 0) | ||
571 | pause->tx_pause = !(netxen_xg_get_xg0_mask(val)); | ||
572 | else | ||
573 | pause->tx_pause = !(netxen_xg_get_xg1_mask(val)); | ||
574 | } else { | ||
575 | printk(KERN_ERR"%s: Unknown board type: %x\n", | ||
576 | netxen_nic_driver_name, adapter->ahw.board_type); | ||
557 | } | 577 | } |
558 | } | 578 | } |
559 | 579 | ||
@@ -561,42 +581,76 @@ static int | |||
561 | netxen_nic_set_pauseparam(struct net_device *dev, | 581 | netxen_nic_set_pauseparam(struct net_device *dev, |
562 | struct ethtool_pauseparam *pause) | 582 | struct ethtool_pauseparam *pause) |
563 | { | 583 | { |
564 | struct netxen_port *port = netdev_priv(dev); | 584 | struct netxen_adapter *adapter = netdev_priv(dev); |
565 | struct netxen_adapter *adapter = port->adapter; | ||
566 | __u32 val; | 585 | __u32 val; |
567 | unsigned int autoneg; | 586 | int port = physical_port[adapter->portnum]; |
568 | |||
569 | /* read mode */ | 587 | /* read mode */ |
570 | if (adapter->ahw.board_type == NETXEN_NIC_GBE) { | 588 | if (adapter->ahw.board_type == NETXEN_NIC_GBE) { |
589 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) | ||
590 | return -EIO; | ||
571 | /* set flow control */ | 591 | /* set flow control */ |
572 | netxen_nic_read_w0(adapter, | 592 | netxen_nic_read_w0(adapter, |
573 | NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum), | 593 | NETXEN_NIU_GB_MAC_CONFIG_0(port), &val); |
574 | (u32 *) & val); | 594 | |
575 | if (pause->tx_pause) | ||
576 | netxen_gb_tx_flowctl(val); | ||
577 | else | ||
578 | netxen_gb_unset_tx_flowctl(val); | ||
579 | if (pause->rx_pause) | 595 | if (pause->rx_pause) |
580 | netxen_gb_rx_flowctl(val); | 596 | netxen_gb_rx_flowctl(val); |
581 | else | 597 | else |
582 | netxen_gb_unset_rx_flowctl(val); | 598 | netxen_gb_unset_rx_flowctl(val); |
583 | 599 | ||
584 | netxen_nic_write_w0(adapter, | 600 | netxen_nic_write_w0(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), |
585 | NETXEN_NIU_GB_MAC_CONFIG_0(port->portnum), | 601 | val); |
586 | *&val); | ||
587 | /* set autoneg */ | 602 | /* set autoneg */ |
588 | autoneg = pause->autoneg; | 603 | netxen_nic_read_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, &val); |
589 | if (adapter->phy_write | 604 | switch (port) { |
590 | && adapter->phy_write(adapter, port->portnum, | 605 | case 0: |
591 | NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, | 606 | if (pause->tx_pause) |
592 | autoneg) != 0) | 607 | netxen_gb_unset_gb0_mask(val); |
608 | else | ||
609 | netxen_gb_set_gb0_mask(val); | ||
610 | break; | ||
611 | case 1: | ||
612 | if (pause->tx_pause) | ||
613 | netxen_gb_unset_gb1_mask(val); | ||
614 | else | ||
615 | netxen_gb_set_gb1_mask(val); | ||
616 | break; | ||
617 | case 2: | ||
618 | if (pause->tx_pause) | ||
619 | netxen_gb_unset_gb2_mask(val); | ||
620 | else | ||
621 | netxen_gb_set_gb2_mask(val); | ||
622 | break; | ||
623 | case 3: | ||
624 | default: | ||
625 | if (pause->tx_pause) | ||
626 | netxen_gb_unset_gb3_mask(val); | ||
627 | else | ||
628 | netxen_gb_set_gb3_mask(val); | ||
629 | break; | ||
630 | } | ||
631 | netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val); | ||
632 | } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { | ||
633 | if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) | ||
593 | return -EIO; | 634 | return -EIO; |
594 | else { | 635 | netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val); |
595 | port->link_autoneg = pause->autoneg; | 636 | if (port == 0) { |
596 | return 0; | 637 | if (pause->tx_pause) |
638 | netxen_xg_unset_xg0_mask(val); | ||
639 | else | ||
640 | netxen_xg_set_xg0_mask(val); | ||
641 | } else { | ||
642 | if (pause->tx_pause) | ||
643 | netxen_xg_unset_xg1_mask(val); | ||
644 | else | ||
645 | netxen_xg_set_xg1_mask(val); | ||
597 | } | 646 | } |
598 | } else | 647 | netxen_nic_write_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, val); |
599 | return -EOPNOTSUPP; | 648 | } else { |
649 | printk(KERN_ERR "%s: Unknown board type: %x\n", | ||
650 | netxen_nic_driver_name, | ||
651 | adapter->ahw.board_type); | ||
652 | } | ||
653 | return 0; | ||
600 | } | 654 | } |
601 | 655 | ||
602 | static int netxen_nic_reg_test(struct net_device *dev) | 656 | static int netxen_nic_reg_test(struct net_device *dev) |
@@ -627,23 +681,12 @@ static void | |||
627 | netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, | 681 | netxen_nic_diag_test(struct net_device *dev, struct ethtool_test *eth_test, |
628 | u64 * data) | 682 | u64 * data) |
629 | { | 683 | { |
630 | if (eth_test->flags == ETH_TEST_FL_OFFLINE) { /* offline tests */ | 684 | memset(data, 0, sizeof(uint64_t) * NETXEN_NIC_TEST_LEN); |
631 | /* link test */ | 685 | if ((data[0] = netxen_nic_reg_test(dev))) |
632 | if ((data[1] = (u64) netxen_nic_test_link(dev))) | 686 | eth_test->flags |= ETH_TEST_FL_FAILED; |
633 | eth_test->flags |= ETH_TEST_FL_FAILED; | 687 | /* link test */ |
634 | 688 | if ((data[1] = (u64) netxen_nic_test_link(dev))) | |
635 | /* register tests */ | 689 | eth_test->flags |= ETH_TEST_FL_FAILED; |
636 | if ((data[0] = netxen_nic_reg_test(dev))) | ||
637 | eth_test->flags |= ETH_TEST_FL_FAILED; | ||
638 | } else { /* online tests */ | ||
639 | /* register tests */ | ||
640 | if((data[0] = netxen_nic_reg_test(dev))) | ||
641 | eth_test->flags |= ETH_TEST_FL_FAILED; | ||
642 | |||
643 | /* link test */ | ||
644 | if ((data[1] = (u64) netxen_nic_test_link(dev))) | ||
645 | eth_test->flags |= ETH_TEST_FL_FAILED; | ||
646 | } | ||
647 | } | 690 | } |
648 | 691 | ||
649 | static void | 692 | static void |
@@ -675,12 +718,13 @@ static void | |||
675 | netxen_nic_get_ethtool_stats(struct net_device *dev, | 718 | netxen_nic_get_ethtool_stats(struct net_device *dev, |
676 | struct ethtool_stats *stats, u64 * data) | 719 | struct ethtool_stats *stats, u64 * data) |
677 | { | 720 | { |
678 | struct netxen_port *port = netdev_priv(dev); | 721 | struct netxen_adapter *adapter = netdev_priv(dev); |
679 | int index; | 722 | int index; |
680 | 723 | ||
681 | for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) { | 724 | for (index = 0; index < NETXEN_NIC_STATS_LEN; index++) { |
682 | char *p = | 725 | char *p = |
683 | (char *)port + netxen_nic_gstrings_stats[index].stat_offset; | 726 | (char *)adapter + |
727 | netxen_nic_gstrings_stats[index].stat_offset; | ||
684 | data[index] = | 728 | data[index] = |
685 | (netxen_nic_gstrings_stats[index].sizeof_stat == | 729 | (netxen_nic_gstrings_stats[index].sizeof_stat == |
686 | sizeof(u64)) ? *(u64 *) p : *(u32 *) p; | 730 | sizeof(u64)) ? *(u64 *) p : *(u32 *) p; |
diff --git a/drivers/net/netxen/netxen_nic_hdr.h b/drivers/net/netxen/netxen_nic_hdr.h index fe8b675f9e72..608e37b349b4 100644 --- a/drivers/net/netxen/netxen_nic_hdr.h +++ b/drivers/net/netxen/netxen_nic_hdr.h | |||
@@ -467,6 +467,8 @@ enum { | |||
467 | #define NETXEN_PCI_OCM1 (0x05100000UL) | 467 | #define NETXEN_PCI_OCM1 (0x05100000UL) |
468 | #define NETXEN_PCI_OCM1_MAX (0x051fffffUL) | 468 | #define NETXEN_PCI_OCM1_MAX (0x051fffffUL) |
469 | #define NETXEN_PCI_CRBSPACE (0x06000000UL) | 469 | #define NETXEN_PCI_CRBSPACE (0x06000000UL) |
470 | #define NETXEN_PCI_128MB_SIZE (0x08000000UL) | ||
471 | #define NETXEN_PCI_32MB_SIZE (0x02000000UL) | ||
470 | 472 | ||
471 | #define NETXEN_CRB_CAM NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_CAM) | 473 | #define NETXEN_CRB_CAM NETXEN_PCI_CRB_WINDOW(NETXEN_HW_PX_MAP_CRB_CAM) |
472 | 474 | ||
@@ -484,6 +486,7 @@ enum { | |||
484 | /* 10 seconds before we give up */ | 486 | /* 10 seconds before we give up */ |
485 | #define NETXEN_NIU_PHY_WAITMAX 50 | 487 | #define NETXEN_NIU_PHY_WAITMAX 50 |
486 | #define NETXEN_NIU_MAX_GBE_PORTS 4 | 488 | #define NETXEN_NIU_MAX_GBE_PORTS 4 |
489 | #define NETXEN_NIU_MAX_XG_PORTS 2 | ||
487 | 490 | ||
488 | #define NETXEN_NIU_MODE (NETXEN_CRB_NIU + 0x00000) | 491 | #define NETXEN_NIU_MODE (NETXEN_CRB_NIU + 0x00000) |
489 | 492 | ||
@@ -527,6 +530,7 @@ enum { | |||
527 | #define NETXEN_NIU_XG_PAUSE_CTL (NETXEN_CRB_NIU + 0x00098) | 530 | #define NETXEN_NIU_XG_PAUSE_CTL (NETXEN_CRB_NIU + 0x00098) |
528 | #define NETXEN_NIU_XG_PAUSE_LEVEL (NETXEN_CRB_NIU + 0x000dc) | 531 | #define NETXEN_NIU_XG_PAUSE_LEVEL (NETXEN_CRB_NIU + 0x000dc) |
529 | #define NETXEN_NIU_XG_SEL (NETXEN_CRB_NIU + 0x00128) | 532 | #define NETXEN_NIU_XG_SEL (NETXEN_CRB_NIU + 0x00128) |
533 | #define NETXEN_NIU_GB_PAUSE_CTL (NETXEN_CRB_NIU + 0x0030c) | ||
530 | 534 | ||
531 | #define NETXEN_NIU_FULL_LEVEL_XG (NETXEN_CRB_NIU + 0x00450) | 535 | #define NETXEN_NIU_FULL_LEVEL_XG (NETXEN_CRB_NIU + 0x00450) |
532 | 536 | ||
@@ -649,11 +653,19 @@ enum { | |||
649 | #define PCIX_MS_WINDOW (0x10204) | 653 | #define PCIX_MS_WINDOW (0x10204) |
650 | #define PCIX_SN_WINDOW (0x10208) | 654 | #define PCIX_SN_WINDOW (0x10208) |
651 | #define PCIX_CRB_WINDOW (0x10210) | 655 | #define PCIX_CRB_WINDOW (0x10210) |
656 | #define PCIX_CRB_WINDOW_F0 (0x10210) | ||
657 | #define PCIX_CRB_WINDOW_F1 (0x10230) | ||
658 | #define PCIX_CRB_WINDOW_F2 (0x10250) | ||
659 | #define PCIX_CRB_WINDOW_F3 (0x10270) | ||
652 | 660 | ||
653 | #define PCIX_TARGET_STATUS (0x10118) | 661 | #define PCIX_TARGET_STATUS (0x10118) |
654 | #define PCIX_TARGET_MASK (0x10128) | 662 | #define PCIX_TARGET_MASK (0x10128) |
655 | 663 | ||
656 | #define PCIX_MSI_F0 (0x13000) | 664 | #define PCIX_MSI_F0 (0x13000) |
665 | #define PCIX_MSI_F1 (0x13004) | ||
666 | #define PCIX_MSI_F2 (0x13008) | ||
667 | #define PCIX_MSI_F3 (0x1300c) | ||
668 | #define PCIX_MSI_F(i) (0x13000+((i)*4)) | ||
657 | 669 | ||
658 | #define PCIX_PS_MEM_SPACE (0x90000) | 670 | #define PCIX_PS_MEM_SPACE (0x90000) |
659 | 671 | ||
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 0fba8f190762..baff17a24d63 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c | |||
@@ -33,10 +33,225 @@ | |||
33 | 33 | ||
34 | #include "netxen_nic.h" | 34 | #include "netxen_nic.h" |
35 | #include "netxen_nic_hw.h" | 35 | #include "netxen_nic_hw.h" |
36 | #define DEFINE_GLOBAL_RECV_CRB | ||
36 | #include "netxen_nic_phan_reg.h" | 37 | #include "netxen_nic_phan_reg.h" |
37 | 38 | ||
39 | |||
38 | #include <net/ip.h> | 40 | #include <net/ip.h> |
39 | 41 | ||
42 | struct netxen_recv_crb recv_crb_registers[] = { | ||
43 | /* | ||
44 | * Instance 0. | ||
45 | */ | ||
46 | { | ||
47 | /* rcv_desc_crb: */ | ||
48 | { | ||
49 | { | ||
50 | /* crb_rcv_producer_offset: */ | ||
51 | NETXEN_NIC_REG(0x100), | ||
52 | /* crb_rcv_consumer_offset: */ | ||
53 | NETXEN_NIC_REG(0x104), | ||
54 | /* crb_gloablrcv_ring: */ | ||
55 | NETXEN_NIC_REG(0x108), | ||
56 | /* crb_rcv_ring_size */ | ||
57 | NETXEN_NIC_REG(0x10c), | ||
58 | |||
59 | }, | ||
60 | /* Jumbo frames */ | ||
61 | { | ||
62 | /* crb_rcv_producer_offset: */ | ||
63 | NETXEN_NIC_REG(0x110), | ||
64 | /* crb_rcv_consumer_offset: */ | ||
65 | NETXEN_NIC_REG(0x114), | ||
66 | /* crb_gloablrcv_ring: */ | ||
67 | NETXEN_NIC_REG(0x118), | ||
68 | /* crb_rcv_ring_size */ | ||
69 | NETXEN_NIC_REG(0x11c), | ||
70 | }, | ||
71 | /* LRO */ | ||
72 | { | ||
73 | /* crb_rcv_producer_offset: */ | ||
74 | NETXEN_NIC_REG(0x120), | ||
75 | /* crb_rcv_consumer_offset: */ | ||
76 | NETXEN_NIC_REG(0x124), | ||
77 | /* crb_gloablrcv_ring: */ | ||
78 | NETXEN_NIC_REG(0x128), | ||
79 | /* crb_rcv_ring_size */ | ||
80 | NETXEN_NIC_REG(0x12c), | ||
81 | } | ||
82 | }, | ||
83 | /* crb_rcvstatus_ring: */ | ||
84 | NETXEN_NIC_REG(0x130), | ||
85 | /* crb_rcv_status_producer: */ | ||
86 | NETXEN_NIC_REG(0x134), | ||
87 | /* crb_rcv_status_consumer: */ | ||
88 | NETXEN_NIC_REG(0x138), | ||
89 | /* crb_rcvpeg_state: */ | ||
90 | NETXEN_NIC_REG(0x13c), | ||
91 | /* crb_status_ring_size */ | ||
92 | NETXEN_NIC_REG(0x140), | ||
93 | |||
94 | }, | ||
95 | /* | ||
96 | * Instance 1, | ||
97 | */ | ||
98 | { | ||
99 | /* rcv_desc_crb: */ | ||
100 | { | ||
101 | { | ||
102 | /* crb_rcv_producer_offset: */ | ||
103 | NETXEN_NIC_REG(0x144), | ||
104 | /* crb_rcv_consumer_offset: */ | ||
105 | NETXEN_NIC_REG(0x148), | ||
106 | /* crb_globalrcv_ring: */ | ||
107 | NETXEN_NIC_REG(0x14c), | ||
108 | /* crb_rcv_ring_size */ | ||
109 | NETXEN_NIC_REG(0x150), | ||
110 | |||
111 | }, | ||
112 | /* Jumbo frames */ | ||
113 | { | ||
114 | /* crb_rcv_producer_offset: */ | ||
115 | NETXEN_NIC_REG(0x154), | ||
116 | /* crb_rcv_consumer_offset: */ | ||
117 | NETXEN_NIC_REG(0x158), | ||
118 | /* crb_globalrcv_ring: */ | ||
119 | NETXEN_NIC_REG(0x15c), | ||
120 | /* crb_rcv_ring_size */ | ||
121 | NETXEN_NIC_REG(0x160), | ||
122 | }, | ||
123 | /* LRO */ | ||
124 | { | ||
125 | /* crb_rcv_producer_offset: */ | ||
126 | NETXEN_NIC_REG(0x164), | ||
127 | /* crb_rcv_consumer_offset: */ | ||
128 | NETXEN_NIC_REG(0x168), | ||
129 | /* crb_globalrcv_ring: */ | ||
130 | NETXEN_NIC_REG(0x16c), | ||
131 | /* crb_rcv_ring_size */ | ||
132 | NETXEN_NIC_REG(0x170), | ||
133 | } | ||
134 | |||
135 | }, | ||
136 | /* crb_rcvstatus_ring: */ | ||
137 | NETXEN_NIC_REG(0x174), | ||
138 | /* crb_rcv_status_producer: */ | ||
139 | NETXEN_NIC_REG(0x178), | ||
140 | /* crb_rcv_status_consumer: */ | ||
141 | NETXEN_NIC_REG(0x17c), | ||
142 | /* crb_rcvpeg_state: */ | ||
143 | NETXEN_NIC_REG(0x180), | ||
144 | /* crb_status_ring_size */ | ||
145 | NETXEN_NIC_REG(0x184), | ||
146 | }, | ||
147 | /* | ||
148 | * Instance 2, | ||
149 | */ | ||
150 | { | ||
151 | { | ||
152 | { | ||
153 | /* crb_rcv_producer_offset: */ | ||
154 | NETXEN_NIC_REG(0x1d8), | ||
155 | /* crb_rcv_consumer_offset: */ | ||
156 | NETXEN_NIC_REG(0x1dc), | ||
157 | /* crb_gloablrcv_ring: */ | ||
158 | NETXEN_NIC_REG(0x1f0), | ||
159 | /* crb_rcv_ring_size */ | ||
160 | NETXEN_NIC_REG(0x1f4), | ||
161 | }, | ||
162 | /* Jumbo frames */ | ||
163 | { | ||
164 | /* crb_rcv_producer_offset: */ | ||
165 | NETXEN_NIC_REG(0x1f8), | ||
166 | /* crb_rcv_consumer_offset: */ | ||
167 | NETXEN_NIC_REG(0x1fc), | ||
168 | /* crb_gloablrcv_ring: */ | ||
169 | NETXEN_NIC_REG(0x200), | ||
170 | /* crb_rcv_ring_size */ | ||
171 | NETXEN_NIC_REG(0x204), | ||
172 | }, | ||
173 | /* LRO */ | ||
174 | { | ||
175 | /* crb_rcv_producer_offset: */ | ||
176 | NETXEN_NIC_REG(0x208), | ||
177 | /* crb_rcv_consumer_offset: */ | ||
178 | NETXEN_NIC_REG(0x20c), | ||
179 | /* crb_gloablrcv_ring: */ | ||
180 | NETXEN_NIC_REG(0x210), | ||
181 | /* crb_rcv_ring_size */ | ||
182 | NETXEN_NIC_REG(0x214), | ||
183 | } | ||
184 | }, | ||
185 | /* crb_rcvstatus_ring: */ | ||
186 | NETXEN_NIC_REG(0x218), | ||
187 | /* crb_rcv_status_producer: */ | ||
188 | NETXEN_NIC_REG(0x21c), | ||
189 | /* crb_rcv_status_consumer: */ | ||
190 | NETXEN_NIC_REG(0x220), | ||
191 | /* crb_rcvpeg_state: */ | ||
192 | NETXEN_NIC_REG(0x224), | ||
193 | /* crb_status_ring_size */ | ||
194 | NETXEN_NIC_REG(0x228), | ||
195 | }, | ||
196 | /* | ||
197 | * Instance 3, | ||
198 | */ | ||
199 | { | ||
200 | { | ||
201 | { | ||
202 | /* crb_rcv_producer_offset: */ | ||
203 | NETXEN_NIC_REG(0x22c), | ||
204 | /* crb_rcv_consumer_offset: */ | ||
205 | NETXEN_NIC_REG(0x230), | ||
206 | /* crb_gloablrcv_ring: */ | ||
207 | NETXEN_NIC_REG(0x234), | ||
208 | /* crb_rcv_ring_size */ | ||
209 | NETXEN_NIC_REG(0x238), | ||
210 | }, | ||
211 | /* Jumbo frames */ | ||
212 | { | ||
213 | /* crb_rcv_producer_offset: */ | ||
214 | NETXEN_NIC_REG(0x23c), | ||
215 | /* crb_rcv_consumer_offset: */ | ||
216 | NETXEN_NIC_REG(0x240), | ||
217 | /* crb_gloablrcv_ring: */ | ||
218 | NETXEN_NIC_REG(0x244), | ||
219 | /* crb_rcv_ring_size */ | ||
220 | NETXEN_NIC_REG(0x248), | ||
221 | }, | ||
222 | /* LRO */ | ||
223 | { | ||
224 | /* crb_rcv_producer_offset: */ | ||
225 | NETXEN_NIC_REG(0x24c), | ||
226 | /* crb_rcv_consumer_offset: */ | ||
227 | NETXEN_NIC_REG(0x250), | ||
228 | /* crb_gloablrcv_ring: */ | ||
229 | NETXEN_NIC_REG(0x254), | ||
230 | /* crb_rcv_ring_size */ | ||
231 | NETXEN_NIC_REG(0x258), | ||
232 | } | ||
233 | }, | ||
234 | /* crb_rcvstatus_ring: */ | ||
235 | NETXEN_NIC_REG(0x25c), | ||
236 | /* crb_rcv_status_producer: */ | ||
237 | NETXEN_NIC_REG(0x260), | ||
238 | /* crb_rcv_status_consumer: */ | ||
239 | NETXEN_NIC_REG(0x264), | ||
240 | /* crb_rcvpeg_state: */ | ||
241 | NETXEN_NIC_REG(0x268), | ||
242 | /* crb_status_ring_size */ | ||
243 | NETXEN_NIC_REG(0x26c), | ||
244 | }, | ||
245 | }; | ||
246 | |||
247 | u64 ctx_addr_sig_regs[][3] = { | ||
248 | {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, | ||
249 | {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, | ||
250 | {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)}, | ||
251 | {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)} | ||
252 | }; | ||
253 | |||
254 | |||
40 | /* PCI Windowing for DDR regions. */ | 255 | /* PCI Windowing for DDR regions. */ |
41 | 256 | ||
42 | #define ADDR_IN_RANGE(addr, low, high) \ | 257 | #define ADDR_IN_RANGE(addr, low, high) \ |
@@ -70,8 +285,7 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter); | |||
70 | 285 | ||
71 | int netxen_nic_set_mac(struct net_device *netdev, void *p) | 286 | int netxen_nic_set_mac(struct net_device *netdev, void *p) |
72 | { | 287 | { |
73 | struct netxen_port *port = netdev_priv(netdev); | 288 | struct netxen_adapter *adapter = netdev_priv(netdev); |
74 | struct netxen_adapter *adapter = port->adapter; | ||
75 | struct sockaddr *addr = p; | 289 | struct sockaddr *addr = p; |
76 | 290 | ||
77 | if (netif_running(netdev)) | 291 | if (netif_running(netdev)) |
@@ -84,7 +298,7 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) | |||
84 | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | 298 | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); |
85 | 299 | ||
86 | if (adapter->macaddr_set) | 300 | if (adapter->macaddr_set) |
87 | adapter->macaddr_set(port, addr->sa_data); | 301 | adapter->macaddr_set(adapter, addr->sa_data); |
88 | 302 | ||
89 | return 0; | 303 | return 0; |
90 | } | 304 | } |
@@ -94,56 +308,19 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) | |||
94 | */ | 308 | */ |
95 | void netxen_nic_set_multi(struct net_device *netdev) | 309 | void netxen_nic_set_multi(struct net_device *netdev) |
96 | { | 310 | { |
97 | struct netxen_port *port = netdev_priv(netdev); | 311 | struct netxen_adapter *adapter = netdev_priv(netdev); |
98 | struct netxen_adapter *adapter = port->adapter; | ||
99 | struct dev_mc_list *mc_ptr; | 312 | struct dev_mc_list *mc_ptr; |
100 | __u32 netxen_mac_addr_cntl_data = 0; | ||
101 | 313 | ||
102 | mc_ptr = netdev->mc_list; | 314 | mc_ptr = netdev->mc_list; |
103 | if (netdev->flags & IFF_PROMISC) { | 315 | if (netdev->flags & IFF_PROMISC) { |
104 | if (adapter->set_promisc) | 316 | if (adapter->set_promisc) |
105 | adapter->set_promisc(adapter, | 317 | adapter->set_promisc(adapter, |
106 | port->portnum, | ||
107 | NETXEN_NIU_PROMISC_MODE); | 318 | NETXEN_NIU_PROMISC_MODE); |
108 | } else { | 319 | } else { |
109 | if (adapter->unset_promisc && | 320 | if (adapter->unset_promisc) |
110 | adapter->ahw.boardcfg.board_type | ||
111 | != NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) | ||
112 | adapter->unset_promisc(adapter, | 321 | adapter->unset_promisc(adapter, |
113 | port->portnum, | ||
114 | NETXEN_NIU_NON_PROMISC_MODE); | 322 | NETXEN_NIU_NON_PROMISC_MODE); |
115 | } | 323 | } |
116 | if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { | ||
117 | netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x03); | ||
118 | netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00); | ||
119 | netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x00); | ||
120 | netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x00); | ||
121 | netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x00); | ||
122 | netxen_nic_mcr_set_enable_xtnd0(netxen_mac_addr_cntl_data); | ||
123 | netxen_nic_mcr_set_enable_xtnd1(netxen_mac_addr_cntl_data); | ||
124 | netxen_nic_mcr_set_enable_xtnd2(netxen_mac_addr_cntl_data); | ||
125 | netxen_nic_mcr_set_enable_xtnd3(netxen_mac_addr_cntl_data); | ||
126 | } else { | ||
127 | netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x00); | ||
128 | netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00); | ||
129 | netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x01); | ||
130 | netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x02); | ||
131 | netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x03); | ||
132 | } | ||
133 | writel(netxen_mac_addr_cntl_data, | ||
134 | NETXEN_CRB_NORMALIZE(adapter, NETXEN_MAC_ADDR_CNTL_REG)); | ||
135 | if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { | ||
136 | writel(netxen_mac_addr_cntl_data, | ||
137 | NETXEN_CRB_NORMALIZE(adapter, | ||
138 | NETXEN_MULTICAST_ADDR_HI_0)); | ||
139 | } else { | ||
140 | writel(netxen_mac_addr_cntl_data, | ||
141 | NETXEN_CRB_NORMALIZE(adapter, | ||
142 | NETXEN_MULTICAST_ADDR_HI_1)); | ||
143 | } | ||
144 | netxen_mac_addr_cntl_data = 0; | ||
145 | writel(netxen_mac_addr_cntl_data, | ||
146 | NETXEN_CRB_NORMALIZE(adapter, NETXEN_NIU_GB_DROP_WRONGADDR)); | ||
147 | } | 324 | } |
148 | 325 | ||
149 | /* | 326 | /* |
@@ -152,8 +329,7 @@ void netxen_nic_set_multi(struct net_device *netdev) | |||
152 | */ | 329 | */ |
153 | int netxen_nic_change_mtu(struct net_device *netdev, int mtu) | 330 | int netxen_nic_change_mtu(struct net_device *netdev, int mtu) |
154 | { | 331 | { |
155 | struct netxen_port *port = netdev_priv(netdev); | 332 | struct netxen_adapter *adapter = netdev_priv(netdev); |
156 | struct netxen_adapter *adapter = port->adapter; | ||
157 | int eff_mtu = mtu + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE; | 333 | int eff_mtu = mtu + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE; |
158 | 334 | ||
159 | if ((eff_mtu > NETXEN_MAX_MTU) || (eff_mtu < NETXEN_MIN_MTU)) { | 335 | if ((eff_mtu > NETXEN_MAX_MTU) || (eff_mtu < NETXEN_MIN_MTU)) { |
@@ -163,7 +339,7 @@ int netxen_nic_change_mtu(struct net_device *netdev, int mtu) | |||
163 | } | 339 | } |
164 | 340 | ||
165 | if (adapter->set_mtu) | 341 | if (adapter->set_mtu) |
166 | adapter->set_mtu(port, mtu); | 342 | adapter->set_mtu(adapter, mtu); |
167 | netdev->mtu = mtu; | 343 | netdev->mtu = mtu; |
168 | 344 | ||
169 | return 0; | 345 | return 0; |
@@ -180,9 +356,9 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
180 | void *addr; | 356 | void *addr; |
181 | int loops = 0, err = 0; | 357 | int loops = 0, err = 0; |
182 | int ctx, ring; | 358 | int ctx, ring; |
183 | u32 card_cmdring = 0; | ||
184 | struct netxen_recv_context *recv_ctx; | 359 | struct netxen_recv_context *recv_ctx; |
185 | struct netxen_rcv_desc_ctx *rcv_desc; | 360 | struct netxen_rcv_desc_ctx *rcv_desc; |
361 | int func_id = adapter->portnum; | ||
186 | 362 | ||
187 | DPRINTK(INFO, "crb_base: %lx %x", NETXEN_PCI_CRBSPACE, | 363 | DPRINTK(INFO, "crb_base: %lx %x", NETXEN_PCI_CRBSPACE, |
188 | PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCI_CRBSPACE)); | 364 | PCI_OFFSET_SECOND_RANGE(adapter, NETXEN_PCI_CRBSPACE)); |
@@ -191,11 +367,6 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
191 | DPRINTK(INFO, "cam RAM: %lx %x", NETXEN_CAM_RAM_BASE, | 367 | DPRINTK(INFO, "cam RAM: %lx %x", NETXEN_CAM_RAM_BASE, |
192 | pci_base_offset(adapter, NETXEN_CAM_RAM_BASE)); | 368 | pci_base_offset(adapter, NETXEN_CAM_RAM_BASE)); |
193 | 369 | ||
194 | /* Window 1 call */ | ||
195 | card_cmdring = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_CMDRING)); | ||
196 | |||
197 | DPRINTK(INFO, "Command Peg sends 0x%x for cmdring base\n", | ||
198 | card_cmdring); | ||
199 | 370 | ||
200 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | 371 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { |
201 | DPRINTK(INFO, "Command Peg ready..waiting for rcv peg\n"); | 372 | DPRINTK(INFO, "Command Peg ready..waiting for rcv peg\n"); |
@@ -229,7 +400,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
229 | (dma_addr_t *) & adapter->ctx_desc_phys_addr, | 400 | (dma_addr_t *) & adapter->ctx_desc_phys_addr, |
230 | &adapter->ctx_desc_pdev); | 401 | &adapter->ctx_desc_pdev); |
231 | 402 | ||
232 | printk("ctx_desc_phys_addr: 0x%llx\n", | 403 | printk(KERN_INFO "ctx_desc_phys_addr: 0x%llx\n", |
233 | (unsigned long long) adapter->ctx_desc_phys_addr); | 404 | (unsigned long long) adapter->ctx_desc_phys_addr); |
234 | if (addr == NULL) { | 405 | if (addr == NULL) { |
235 | DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); | 406 | DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); |
@@ -238,6 +409,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
238 | } | 409 | } |
239 | memset(addr, 0, sizeof(struct netxen_ring_ctx)); | 410 | memset(addr, 0, sizeof(struct netxen_ring_ctx)); |
240 | adapter->ctx_desc = (struct netxen_ring_ctx *)addr; | 411 | adapter->ctx_desc = (struct netxen_ring_ctx *)addr; |
412 | adapter->ctx_desc->ctx_id = cpu_to_le32(adapter->portnum); | ||
241 | adapter->ctx_desc->cmd_consumer_offset = | 413 | adapter->ctx_desc->cmd_consumer_offset = |
242 | cpu_to_le64(adapter->ctx_desc_phys_addr + | 414 | cpu_to_le64(adapter->ctx_desc_phys_addr + |
243 | sizeof(struct netxen_ring_ctx)); | 415 | sizeof(struct netxen_ring_ctx)); |
@@ -249,7 +421,7 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
249 | adapter->max_tx_desc_count, | 421 | adapter->max_tx_desc_count, |
250 | (dma_addr_t *) & hw->cmd_desc_phys_addr, | 422 | (dma_addr_t *) & hw->cmd_desc_phys_addr, |
251 | &adapter->ahw.cmd_desc_pdev); | 423 | &adapter->ahw.cmd_desc_pdev); |
252 | printk("cmd_desc_phys_addr: 0x%llx\n", | 424 | printk(KERN_INFO "cmd_desc_phys_addr: 0x%llx\n", |
253 | (unsigned long long) hw->cmd_desc_phys_addr); | 425 | (unsigned long long) hw->cmd_desc_phys_addr); |
254 | 426 | ||
255 | if (addr == NULL) { | 427 | if (addr == NULL) { |
@@ -308,11 +480,11 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
308 | /* Window = 1 */ | 480 | /* Window = 1 */ |
309 | 481 | ||
310 | writel(lower32(adapter->ctx_desc_phys_addr), | 482 | writel(lower32(adapter->ctx_desc_phys_addr), |
311 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO)); | 483 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO(func_id))); |
312 | writel(upper32(adapter->ctx_desc_phys_addr), | 484 | writel(upper32(adapter->ctx_desc_phys_addr), |
313 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI)); | 485 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI(func_id))); |
314 | writel(NETXEN_CTX_SIGNATURE, | 486 | writel(NETXEN_CTX_SIGNATURE | func_id, |
315 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG)); | 487 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG(func_id))); |
316 | return err; | 488 | return err; |
317 | } | 489 | } |
318 | 490 | ||
@@ -339,10 +511,6 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) | |||
339 | adapter->ahw.cmd_desc_phys_addr); | 511 | adapter->ahw.cmd_desc_phys_addr); |
340 | adapter->ahw.cmd_desc_head = NULL; | 512 | adapter->ahw.cmd_desc_head = NULL; |
341 | } | 513 | } |
342 | /* Special handling: there are 2 ports on this board */ | ||
343 | if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { | ||
344 | adapter->ahw.max_ports = 2; | ||
345 | } | ||
346 | 514 | ||
347 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | 515 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { |
348 | recv_ctx = &adapter->recv_ctx[ctx]; | 516 | recv_ctx = &adapter->recv_ctx[ctx]; |
@@ -385,7 +553,6 @@ void netxen_tso_check(struct netxen_adapter *adapter, | |||
385 | return; | 553 | return; |
386 | } | 554 | } |
387 | } | 555 | } |
388 | adapter->stats.xmitcsummed++; | ||
389 | desc->tcp_hdr_offset = skb_transport_offset(skb); | 556 | desc->tcp_hdr_offset = skb_transport_offset(skb); |
390 | desc->ip_hdr_offset = skb_network_offset(skb); | 557 | desc->ip_hdr_offset = skb_network_offset(skb); |
391 | } | 558 | } |
@@ -475,7 +642,30 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) | |||
475 | 642 | ||
476 | if (adapter->curr_window == wndw) | 643 | if (adapter->curr_window == wndw) |
477 | return; | 644 | return; |
478 | 645 | switch(adapter->ahw.pci_func) { | |
646 | case 0: | ||
647 | offset = PCI_OFFSET_SECOND_RANGE(adapter, | ||
648 | NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW)); | ||
649 | break; | ||
650 | case 1: | ||
651 | offset = PCI_OFFSET_SECOND_RANGE(adapter, | ||
652 | NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F1)); | ||
653 | break; | ||
654 | case 2: | ||
655 | offset = PCI_OFFSET_SECOND_RANGE(adapter, | ||
656 | NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F2)); | ||
657 | break; | ||
658 | case 3: | ||
659 | offset = PCI_OFFSET_SECOND_RANGE(adapter, | ||
660 | NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW_F3)); | ||
661 | break; | ||
662 | default: | ||
663 | printk(KERN_INFO "Changing the window for PCI function" | ||
664 | "%d\n", adapter->ahw.pci_func); | ||
665 | offset = PCI_OFFSET_SECOND_RANGE(adapter, | ||
666 | NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW)); | ||
667 | break; | ||
668 | } | ||
479 | /* | 669 | /* |
480 | * Move the CRB window. | 670 | * Move the CRB window. |
481 | * We need to write to the "direct access" region of PCI | 671 | * We need to write to the "direct access" region of PCI |
@@ -484,9 +674,6 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) | |||
484 | * register address is received by PCI. The direct region bypasses | 674 | * register address is received by PCI. The direct region bypasses |
485 | * the CRB bus. | 675 | * the CRB bus. |
486 | */ | 676 | */ |
487 | offset = | ||
488 | PCI_OFFSET_SECOND_RANGE(adapter, | ||
489 | NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW)); | ||
490 | 677 | ||
491 | if (wndw & 0x1) | 678 | if (wndw & 0x1) |
492 | wndw = NETXEN_WINDOW_ONE; | 679 | wndw = NETXEN_WINDOW_ONE; |
@@ -504,7 +691,10 @@ void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) | |||
504 | count++; | 691 | count++; |
505 | } | 692 | } |
506 | 693 | ||
507 | adapter->curr_window = wndw; | 694 | if (wndw == NETXEN_WINDOW_ONE) |
695 | adapter->curr_window = 1; | ||
696 | else | ||
697 | adapter->curr_window = 0; | ||
508 | } | 698 | } |
509 | 699 | ||
510 | void netxen_load_firmware(struct netxen_adapter *adapter) | 700 | void netxen_load_firmware(struct netxen_adapter *adapter) |
@@ -749,6 +939,17 @@ netxen_nic_pci_set_window(struct netxen_adapter *adapter, | |||
749 | return addr; | 939 | return addr; |
750 | } | 940 | } |
751 | 941 | ||
942 | int | ||
943 | netxen_nic_erase_pxe(struct netxen_adapter *adapter) | ||
944 | { | ||
945 | if (netxen_rom_fast_write(adapter, PXE_START, 0) == -1) { | ||
946 | printk(KERN_ERR "%s: erase pxe failed\n", | ||
947 | netxen_nic_driver_name); | ||
948 | return -1; | ||
949 | } | ||
950 | return 0; | ||
951 | } | ||
952 | |||
752 | int netxen_nic_get_board_info(struct netxen_adapter *adapter) | 953 | int netxen_nic_get_board_info(struct netxen_adapter *adapter) |
753 | { | 954 | { |
754 | int rv = 0; | 955 | int rv = 0; |
@@ -810,43 +1011,29 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter) | |||
810 | 1011 | ||
811 | /* NIU access sections */ | 1012 | /* NIU access sections */ |
812 | 1013 | ||
813 | int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu) | 1014 | int netxen_nic_set_mtu_gb(struct netxen_adapter *adapter, int new_mtu) |
814 | { | 1015 | { |
815 | struct netxen_adapter *adapter = port->adapter; | ||
816 | netxen_nic_write_w0(adapter, | 1016 | netxen_nic_write_w0(adapter, |
817 | NETXEN_NIU_GB_MAX_FRAME_SIZE(port->portnum), | 1017 | NETXEN_NIU_GB_MAX_FRAME_SIZE( |
818 | new_mtu); | 1018 | physical_port[adapter->portnum]), new_mtu); |
819 | return 0; | 1019 | return 0; |
820 | } | 1020 | } |
821 | 1021 | ||
822 | int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu) | 1022 | int netxen_nic_set_mtu_xgb(struct netxen_adapter *adapter, int new_mtu) |
823 | { | 1023 | { |
824 | struct netxen_adapter *adapter = port->adapter; | ||
825 | new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE; | 1024 | new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE; |
826 | if (port->portnum == 0) | 1025 | if (physical_port[adapter->portnum] == 0) |
827 | netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu); | 1026 | netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, |
828 | else if (port->portnum == 1) | 1027 | new_mtu); |
829 | netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, new_mtu); | 1028 | else |
1029 | netxen_nic_write_w0(adapter, NETXEN_NIU_XG1_MAX_FRAME_SIZE, | ||
1030 | new_mtu); | ||
830 | return 0; | 1031 | return 0; |
831 | } | 1032 | } |
832 | 1033 | ||
833 | void netxen_nic_init_niu_gb(struct netxen_adapter *adapter) | 1034 | void netxen_nic_init_niu_gb(struct netxen_adapter *adapter) |
834 | { | 1035 | { |
835 | int portno; | 1036 | netxen_niu_gbe_init_port(adapter, physical_port[adapter->portnum]); |
836 | for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) | ||
837 | netxen_niu_gbe_init_port(adapter, portno); | ||
838 | } | ||
839 | |||
840 | void netxen_nic_stop_all_ports(struct netxen_adapter *adapter) | ||
841 | { | ||
842 | int port_nr; | ||
843 | struct netxen_port *port; | ||
844 | |||
845 | for (port_nr = 0; port_nr < adapter->ahw.max_ports; port_nr++) { | ||
846 | port = adapter->port[port_nr]; | ||
847 | if (adapter->stop_port) | ||
848 | adapter->stop_port(adapter, port->portnum); | ||
849 | } | ||
850 | } | 1037 | } |
851 | 1038 | ||
852 | void | 1039 | void |
@@ -865,9 +1052,8 @@ netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, | |||
865 | } | 1052 | } |
866 | } | 1053 | } |
867 | 1054 | ||
868 | void netxen_nic_set_link_parameters(struct netxen_port *port) | 1055 | void netxen_nic_set_link_parameters(struct netxen_adapter *adapter) |
869 | { | 1056 | { |
870 | struct netxen_adapter *adapter = port->adapter; | ||
871 | __u32 status; | 1057 | __u32 status; |
872 | __u32 autoneg; | 1058 | __u32 autoneg; |
873 | __u32 mode; | 1059 | __u32 mode; |
@@ -876,47 +1062,47 @@ void netxen_nic_set_link_parameters(struct netxen_port *port) | |||
876 | if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */ | 1062 | if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */ |
877 | if (adapter->phy_read | 1063 | if (adapter->phy_read |
878 | && adapter-> | 1064 | && adapter-> |
879 | phy_read(adapter, port->portnum, | 1065 | phy_read(adapter, |
880 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, | 1066 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
881 | &status) == 0) { | 1067 | &status) == 0) { |
882 | if (netxen_get_phy_link(status)) { | 1068 | if (netxen_get_phy_link(status)) { |
883 | switch (netxen_get_phy_speed(status)) { | 1069 | switch (netxen_get_phy_speed(status)) { |
884 | case 0: | 1070 | case 0: |
885 | port->link_speed = SPEED_10; | 1071 | adapter->link_speed = SPEED_10; |
886 | break; | 1072 | break; |
887 | case 1: | 1073 | case 1: |
888 | port->link_speed = SPEED_100; | 1074 | adapter->link_speed = SPEED_100; |
889 | break; | 1075 | break; |
890 | case 2: | 1076 | case 2: |
891 | port->link_speed = SPEED_1000; | 1077 | adapter->link_speed = SPEED_1000; |
892 | break; | 1078 | break; |
893 | default: | 1079 | default: |
894 | port->link_speed = -1; | 1080 | adapter->link_speed = -1; |
895 | break; | 1081 | break; |
896 | } | 1082 | } |
897 | switch (netxen_get_phy_duplex(status)) { | 1083 | switch (netxen_get_phy_duplex(status)) { |
898 | case 0: | 1084 | case 0: |
899 | port->link_duplex = DUPLEX_HALF; | 1085 | adapter->link_duplex = DUPLEX_HALF; |
900 | break; | 1086 | break; |
901 | case 1: | 1087 | case 1: |
902 | port->link_duplex = DUPLEX_FULL; | 1088 | adapter->link_duplex = DUPLEX_FULL; |
903 | break; | 1089 | break; |
904 | default: | 1090 | default: |
905 | port->link_duplex = -1; | 1091 | adapter->link_duplex = -1; |
906 | break; | 1092 | break; |
907 | } | 1093 | } |
908 | if (adapter->phy_read | 1094 | if (adapter->phy_read |
909 | && adapter-> | 1095 | && adapter-> |
910 | phy_read(adapter, port->portnum, | 1096 | phy_read(adapter, |
911 | NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, | 1097 | NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, |
912 | &autoneg) != 0) | 1098 | &autoneg) != 0) |
913 | port->link_autoneg = autoneg; | 1099 | adapter->link_autoneg = autoneg; |
914 | } else | 1100 | } else |
915 | goto link_down; | 1101 | goto link_down; |
916 | } else { | 1102 | } else { |
917 | link_down: | 1103 | link_down: |
918 | port->link_speed = -1; | 1104 | adapter->link_speed = -1; |
919 | port->link_duplex = -1; | 1105 | adapter->link_duplex = -1; |
920 | } | 1106 | } |
921 | } | 1107 | } |
922 | } | 1108 | } |
@@ -930,7 +1116,7 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) | |||
930 | char brd_name[NETXEN_MAX_SHORT_NAME]; | 1116 | char brd_name[NETXEN_MAX_SHORT_NAME]; |
931 | struct netxen_new_user_info user_info; | 1117 | struct netxen_new_user_info user_info; |
932 | int i, addr = USER_START; | 1118 | int i, addr = USER_START; |
933 | u32 *ptr32; | 1119 | __le32 *ptr32; |
934 | 1120 | ||
935 | struct netxen_board_info *board_info = &(adapter->ahw.boardcfg); | 1121 | struct netxen_board_info *board_info = &(adapter->ahw.boardcfg); |
936 | if (board_info->magic != NETXEN_BDINFO_MAGIC) { | 1122 | if (board_info->magic != NETXEN_BDINFO_MAGIC) { |
@@ -956,7 +1142,6 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter) | |||
956 | netxen_nic_driver_name); | 1142 | netxen_nic_driver_name); |
957 | return; | 1143 | return; |
958 | } | 1144 | } |
959 | *ptr32 = le32_to_cpu(*ptr32); | ||
960 | ptr32++; | 1145 | ptr32++; |
961 | addr += sizeof(u32); | 1146 | addr += sizeof(u32); |
962 | } | 1147 | } |
diff --git a/drivers/net/netxen/netxen_nic_hw.h b/drivers/net/netxen/netxen_nic_hw.h index ab1112eb1b0d..245bf13c7ba2 100644 --- a/drivers/net/netxen/netxen_nic_hw.h +++ b/drivers/net/netxen/netxen_nic_hw.h | |||
@@ -6,12 +6,12 @@ | |||
6 | * modify it under the terms of the GNU General Public License | 6 | * modify it under the terms of the GNU General Public License |
7 | * as published by the Free Software Foundation; either version 2 | 7 | * as published by the Free Software Foundation; either version 2 |
8 | * of the License, or (at your option) any later version. | 8 | * of the License, or (at your option) any later version. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, but | 10 | * This program is distributed in the hope that it will be useful, but |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, | 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
@@ -87,7 +87,7 @@ struct netxen_adapter; | |||
87 | *(u32 *)Y = readl((void __iomem*) addr); | 87 | *(u32 *)Y = readl((void __iomem*) addr); |
88 | 88 | ||
89 | struct netxen_port; | 89 | struct netxen_port; |
90 | void netxen_nic_set_link_parameters(struct netxen_port *port); | 90 | void netxen_nic_set_link_parameters(struct netxen_adapter *adapter); |
91 | void netxen_nic_flash_print(struct netxen_adapter *adapter); | 91 | void netxen_nic_flash_print(struct netxen_adapter *adapter); |
92 | int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, | 92 | int netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, |
93 | void *data, int len); | 93 | void *data, int len); |
@@ -220,6 +220,69 @@ typedef enum { | |||
220 | _netxen_crb_get_bit(config_word, 1) | 220 | _netxen_crb_get_bit(config_word, 1) |
221 | #define netxen_get_gb_mii_mgmt_notvalid(config_word) \ | 221 | #define netxen_get_gb_mii_mgmt_notvalid(config_word) \ |
222 | _netxen_crb_get_bit(config_word, 2) | 222 | _netxen_crb_get_bit(config_word, 2) |
223 | /* | ||
224 | * NIU XG Pause Ctl Register | ||
225 | * | ||
226 | * Bit 0 : xg0_mask => 1:disable tx pause frames | ||
227 | * Bit 1 : xg0_request => 1:request single pause frame | ||
228 | * Bit 2 : xg0_on_off => 1:request is pause on, 0:off | ||
229 | * Bit 3 : xg1_mask => 1:disable tx pause frames | ||
230 | * Bit 4 : xg1_request => 1:request single pause frame | ||
231 | * Bit 5 : xg1_on_off => 1:request is pause on, 0:off | ||
232 | */ | ||
233 | |||
234 | #define netxen_xg_set_xg0_mask(config_word) \ | ||
235 | ((config_word) |= 1 << 0) | ||
236 | #define netxen_xg_set_xg1_mask(config_word) \ | ||
237 | ((config_word) |= 1 << 3) | ||
238 | |||
239 | #define netxen_xg_get_xg0_mask(config_word) \ | ||
240 | _netxen_crb_get_bit((config_word), 0) | ||
241 | #define netxen_xg_get_xg1_mask(config_word) \ | ||
242 | _netxen_crb_get_bit((config_word), 3) | ||
243 | |||
244 | #define netxen_xg_unset_xg0_mask(config_word) \ | ||
245 | ((config_word) &= ~(1 << 0)) | ||
246 | #define netxen_xg_unset_xg1_mask(config_word) \ | ||
247 | ((config_word) &= ~(1 << 3)) | ||
248 | |||
249 | /* | ||
250 | * NIU XG Pause Ctl Register | ||
251 | * | ||
252 | * Bit 0 : xg0_mask => 1:disable tx pause frames | ||
253 | * Bit 1 : xg0_request => 1:request single pause frame | ||
254 | * Bit 2 : xg0_on_off => 1:request is pause on, 0:off | ||
255 | * Bit 3 : xg1_mask => 1:disable tx pause frames | ||
256 | * Bit 4 : xg1_request => 1:request single pause frame | ||
257 | * Bit 5 : xg1_on_off => 1:request is pause on, 0:off | ||
258 | */ | ||
259 | #define netxen_gb_set_gb0_mask(config_word) \ | ||
260 | ((config_word) |= 1 << 0) | ||
261 | #define netxen_gb_set_gb1_mask(config_word) \ | ||
262 | ((config_word) |= 1 << 2) | ||
263 | #define netxen_gb_set_gb2_mask(config_word) \ | ||
264 | ((config_word) |= 1 << 4) | ||
265 | #define netxen_gb_set_gb3_mask(config_word) \ | ||
266 | ((config_word) |= 1 << 6) | ||
267 | |||
268 | #define netxen_gb_get_gb0_mask(config_word) \ | ||
269 | _netxen_crb_get_bit((config_word), 0) | ||
270 | #define netxen_gb_get_gb1_mask(config_word) \ | ||
271 | _netxen_crb_get_bit((config_word), 2) | ||
272 | #define netxen_gb_get_gb2_mask(config_word) \ | ||
273 | _netxen_crb_get_bit((config_word), 4) | ||
274 | #define netxen_gb_get_gb3_mask(config_word) \ | ||
275 | _netxen_crb_get_bit((config_word), 6) | ||
276 | |||
277 | #define netxen_gb_unset_gb0_mask(config_word) \ | ||
278 | ((config_word) &= ~(1 << 0)) | ||
279 | #define netxen_gb_unset_gb1_mask(config_word) \ | ||
280 | ((config_word) &= ~(1 << 2)) | ||
281 | #define netxen_gb_unset_gb2_mask(config_word) \ | ||
282 | ((config_word) &= ~(1 << 4)) | ||
283 | #define netxen_gb_unset_gb3_mask(config_word) \ | ||
284 | ((config_word) &= ~(1 << 6)) | ||
285 | |||
223 | 286 | ||
224 | /* | 287 | /* |
225 | * PHY-Specific MII control/status registers. | 288 | * PHY-Specific MII control/status registers. |
@@ -452,21 +515,21 @@ typedef enum { | |||
452 | ((config) |= (((val) & 0x0f) << 28)) | 515 | ((config) |= (((val) & 0x0f) << 28)) |
453 | 516 | ||
454 | /* Set promiscuous mode for a GbE interface */ | 517 | /* Set promiscuous mode for a GbE interface */ |
455 | int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port, | 518 | int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, |
456 | netxen_niu_prom_mode_t mode); | 519 | netxen_niu_prom_mode_t mode); |
457 | int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, | 520 | int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, |
458 | int port, netxen_niu_prom_mode_t mode); | 521 | netxen_niu_prom_mode_t mode); |
459 | 522 | ||
460 | /* get/set the MAC address for a given MAC */ | 523 | /* get/set the MAC address for a given MAC */ |
461 | int netxen_niu_macaddr_get(struct netxen_adapter *adapter, int port, | 524 | int netxen_niu_macaddr_get(struct netxen_adapter *adapter, |
462 | netxen_ethernet_macaddr_t * addr); | 525 | netxen_ethernet_macaddr_t * addr); |
463 | int netxen_niu_macaddr_set(struct netxen_port *port, | 526 | int netxen_niu_macaddr_set(struct netxen_adapter *adapter, |
464 | netxen_ethernet_macaddr_t addr); | 527 | netxen_ethernet_macaddr_t addr); |
465 | 528 | ||
466 | /* XG versons */ | 529 | /* XG versons */ |
467 | int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int port, | 530 | int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, |
468 | netxen_ethernet_macaddr_t * addr); | 531 | netxen_ethernet_macaddr_t * addr); |
469 | int netxen_niu_xg_macaddr_set(struct netxen_port *port, | 532 | int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, |
470 | netxen_ethernet_macaddr_t addr); | 533 | netxen_ethernet_macaddr_t addr); |
471 | 534 | ||
472 | /* Generic enable for GbE ports. Will detect the speed of the link. */ | 535 | /* Generic enable for GbE ports. Will detect the speed of the link. */ |
@@ -475,8 +538,8 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port); | |||
475 | int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); | 538 | int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port); |
476 | 539 | ||
477 | /* Disable a GbE interface */ | 540 | /* Disable a GbE interface */ |
478 | int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port); | 541 | int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter); |
479 | 542 | ||
480 | int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port); | 543 | int netxen_niu_disable_xg_port(struct netxen_adapter *adapter); |
481 | 544 | ||
482 | #endif /* __NETXEN_NIC_HW_H_ */ | 545 | #endif /* __NETXEN_NIC_HW_H_ */ |
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 5cd40562da7c..cf0e96adfe44 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c | |||
@@ -139,7 +139,7 @@ int netxen_init_firmware(struct netxen_adapter *adapter) | |||
139 | return err; | 139 | return err; |
140 | } | 140 | } |
141 | /* Window 1 call */ | 141 | /* Window 1 call */ |
142 | writel(MPORT_SINGLE_FUNCTION_MODE, | 142 | writel(MPORT_MULTI_FUNCTION_MODE, |
143 | NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE)); | 143 | NETXEN_CRB_NORMALIZE(adapter, CRB_MPORT_MODE)); |
144 | writel(PHAN_INITIALIZE_ACK, | 144 | writel(PHAN_INITIALIZE_ACK, |
145 | NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); | 145 | NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); |
@@ -226,7 +226,6 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter) | |||
226 | adapter->unset_promisc = netxen_niu_set_promiscuous_mode; | 226 | adapter->unset_promisc = netxen_niu_set_promiscuous_mode; |
227 | adapter->phy_read = netxen_niu_gbe_phy_read; | 227 | adapter->phy_read = netxen_niu_gbe_phy_read; |
228 | adapter->phy_write = netxen_niu_gbe_phy_write; | 228 | adapter->phy_write = netxen_niu_gbe_phy_write; |
229 | adapter->init_port = netxen_niu_gbe_init_port; | ||
230 | adapter->init_niu = netxen_nic_init_niu_gb; | 229 | adapter->init_niu = netxen_nic_init_niu_gb; |
231 | adapter->stop_port = netxen_niu_disable_gbe_port; | 230 | adapter->stop_port = netxen_niu_disable_gbe_port; |
232 | break; | 231 | break; |
@@ -277,8 +276,8 @@ u32 netxen_decode_crb_addr(u32 addr) | |||
277 | return (pci_base + offset); | 276 | return (pci_base + offset); |
278 | } | 277 | } |
279 | 278 | ||
280 | static long rom_max_timeout = 10000; | 279 | static long rom_max_timeout = 100; |
281 | static long rom_lock_timeout = 1000000; | 280 | static long rom_lock_timeout = 10000; |
282 | static long rom_write_timeout = 700; | 281 | static long rom_write_timeout = 700; |
283 | 282 | ||
284 | static inline int rom_lock(struct netxen_adapter *adapter) | 283 | static inline int rom_lock(struct netxen_adapter *adapter) |
@@ -438,9 +437,9 @@ do_rom_fast_read_words(struct netxen_adapter *adapter, int addr, | |||
438 | 437 | ||
439 | for (addridx = addr; addridx < (addr + size); addridx += 4) { | 438 | for (addridx = addr; addridx < (addr + size); addridx += 4) { |
440 | ret = do_rom_fast_read(adapter, addridx, (int *)bytes); | 439 | ret = do_rom_fast_read(adapter, addridx, (int *)bytes); |
441 | *(int *)bytes = cpu_to_le32(*(int *)bytes); | ||
442 | if (ret != 0) | 440 | if (ret != 0) |
443 | break; | 441 | break; |
442 | *(int *)bytes = cpu_to_le32(*(int *)bytes); | ||
444 | bytes += 4; | 443 | bytes += 4; |
445 | } | 444 | } |
446 | 445 | ||
@@ -499,7 +498,6 @@ static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, | |||
499 | int data; | 498 | int data; |
500 | 499 | ||
501 | data = le32_to_cpu((*(u32*)bytes)); | 500 | data = le32_to_cpu((*(u32*)bytes)); |
502 | |||
503 | ret = do_rom_fast_write(adapter, addridx, data); | 501 | ret = do_rom_fast_write(adapter, addridx, data); |
504 | if (ret < 0) | 502 | if (ret < 0) |
505 | return ret; | 503 | return ret; |
@@ -953,7 +951,8 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val) | |||
953 | 951 | ||
954 | if (!pegtune_val) { | 952 | if (!pegtune_val) { |
955 | val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); | 953 | val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); |
956 | while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) { | 954 | while (val != PHAN_INITIALIZE_COMPLETE && |
955 | val != PHAN_INITIALIZE_ACK && loops < 200000) { | ||
957 | udelay(100); | 956 | udelay(100); |
958 | schedule(); | 957 | schedule(); |
959 | val = | 958 | val = |
@@ -990,9 +989,7 @@ int netxen_nic_rx_has_work(struct netxen_adapter *adapter) | |||
990 | 989 | ||
991 | static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) | 990 | static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) |
992 | { | 991 | { |
993 | int port_num; | 992 | struct net_device *netdev = adapter->netdev; |
994 | struct netxen_port *port; | ||
995 | struct net_device *netdev; | ||
996 | uint32_t temp, temp_state, temp_val; | 993 | uint32_t temp, temp_state, temp_val; |
997 | int rv = 0; | 994 | int rv = 0; |
998 | 995 | ||
@@ -1006,14 +1003,9 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) | |||
1006 | "%s: Device temperature %d degrees C exceeds" | 1003 | "%s: Device temperature %d degrees C exceeds" |
1007 | " maximum allowed. Hardware has been shut down.\n", | 1004 | " maximum allowed. Hardware has been shut down.\n", |
1008 | netxen_nic_driver_name, temp_val); | 1005 | netxen_nic_driver_name, temp_val); |
1009 | for (port_num = 0; port_num < adapter->ahw.max_ports; | ||
1010 | port_num++) { | ||
1011 | port = adapter->port[port_num]; | ||
1012 | netdev = port->netdev; | ||
1013 | 1006 | ||
1014 | netif_carrier_off(netdev); | 1007 | netif_carrier_off(netdev); |
1015 | netif_stop_queue(netdev); | 1008 | netif_stop_queue(netdev); |
1016 | } | ||
1017 | rv = 1; | 1009 | rv = 1; |
1018 | } else if (temp_state == NX_TEMP_WARN) { | 1010 | } else if (temp_state == NX_TEMP_WARN) { |
1019 | if (adapter->temp == NX_TEMP_NORMAL) { | 1011 | if (adapter->temp == NX_TEMP_NORMAL) { |
@@ -1037,29 +1029,23 @@ static inline int netxen_nic_check_temp(struct netxen_adapter *adapter) | |||
1037 | 1029 | ||
1038 | void netxen_watchdog_task(struct work_struct *work) | 1030 | void netxen_watchdog_task(struct work_struct *work) |
1039 | { | 1031 | { |
1040 | int port_num; | ||
1041 | struct netxen_port *port; | ||
1042 | struct net_device *netdev; | 1032 | struct net_device *netdev; |
1043 | struct netxen_adapter *adapter = | 1033 | struct netxen_adapter *adapter = |
1044 | container_of(work, struct netxen_adapter, watchdog_task); | 1034 | container_of(work, struct netxen_adapter, watchdog_task); |
1045 | 1035 | ||
1046 | if (netxen_nic_check_temp(adapter)) | 1036 | if ((adapter->portnum == 0) && netxen_nic_check_temp(adapter)) |
1047 | return; | 1037 | return; |
1048 | 1038 | ||
1049 | for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) { | 1039 | netdev = adapter->netdev; |
1050 | port = adapter->port[port_num]; | 1040 | if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) { |
1051 | netdev = port->netdev; | 1041 | printk(KERN_INFO "%s port %d, %s carrier is now ok\n", |
1052 | 1042 | netxen_nic_driver_name, adapter->portnum, netdev->name); | |
1053 | if ((netif_running(netdev)) && !netif_carrier_ok(netdev)) { | 1043 | netif_carrier_on(netdev); |
1054 | printk(KERN_INFO "%s port %d, %s carrier is now ok\n", | ||
1055 | netxen_nic_driver_name, port_num, netdev->name); | ||
1056 | netif_carrier_on(netdev); | ||
1057 | } | ||
1058 | |||
1059 | if (netif_queue_stopped(netdev)) | ||
1060 | netif_wake_queue(netdev); | ||
1061 | } | 1044 | } |
1062 | 1045 | ||
1046 | if (netif_queue_stopped(netdev)) | ||
1047 | netif_wake_queue(netdev); | ||
1048 | |||
1063 | if (adapter->handle_phy_intr) | 1049 | if (adapter->handle_phy_intr) |
1064 | adapter->handle_phy_intr(adapter); | 1050 | adapter->handle_phy_intr(adapter); |
1065 | mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); | 1051 | mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); |
@@ -1074,9 +1060,8 @@ void | |||
1074 | netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, | 1060 | netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, |
1075 | struct status_desc *desc) | 1061 | struct status_desc *desc) |
1076 | { | 1062 | { |
1077 | struct netxen_port *port = adapter->port[netxen_get_sts_port(desc)]; | 1063 | struct pci_dev *pdev = adapter->pdev; |
1078 | struct pci_dev *pdev = port->pdev; | 1064 | struct net_device *netdev = adapter->netdev; |
1079 | struct net_device *netdev = port->netdev; | ||
1080 | int index = netxen_get_sts_refhandle(desc); | 1065 | int index = netxen_get_sts_refhandle(desc); |
1081 | struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]); | 1066 | struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]); |
1082 | struct netxen_rx_buffer *buffer; | 1067 | struct netxen_rx_buffer *buffer; |
@@ -1126,7 +1111,7 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, | |||
1126 | skb = (struct sk_buff *)buffer->skb; | 1111 | skb = (struct sk_buff *)buffer->skb; |
1127 | 1112 | ||
1128 | if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) { | 1113 | if (likely(netxen_get_sts_status(desc) == STATUS_CKSUM_OK)) { |
1129 | port->stats.csummed++; | 1114 | adapter->stats.csummed++; |
1130 | skb->ip_summed = CHECKSUM_UNNECESSARY; | 1115 | skb->ip_summed = CHECKSUM_UNNECESSARY; |
1131 | } | 1116 | } |
1132 | if (desc_ctx == RCV_DESC_LRO_CTXID) { | 1117 | if (desc_ctx == RCV_DESC_LRO_CTXID) { |
@@ -1146,27 +1131,27 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, | |||
1146 | */ | 1131 | */ |
1147 | switch (ret) { | 1132 | switch (ret) { |
1148 | case NET_RX_SUCCESS: | 1133 | case NET_RX_SUCCESS: |
1149 | port->stats.uphappy++; | 1134 | adapter->stats.uphappy++; |
1150 | break; | 1135 | break; |
1151 | 1136 | ||
1152 | case NET_RX_CN_LOW: | 1137 | case NET_RX_CN_LOW: |
1153 | port->stats.uplcong++; | 1138 | adapter->stats.uplcong++; |
1154 | break; | 1139 | break; |
1155 | 1140 | ||
1156 | case NET_RX_CN_MOD: | 1141 | case NET_RX_CN_MOD: |
1157 | port->stats.upmcong++; | 1142 | adapter->stats.upmcong++; |
1158 | break; | 1143 | break; |
1159 | 1144 | ||
1160 | case NET_RX_CN_HIGH: | 1145 | case NET_RX_CN_HIGH: |
1161 | port->stats.uphcong++; | 1146 | adapter->stats.uphcong++; |
1162 | break; | 1147 | break; |
1163 | 1148 | ||
1164 | case NET_RX_DROP: | 1149 | case NET_RX_DROP: |
1165 | port->stats.updropped++; | 1150 | adapter->stats.updropped++; |
1166 | break; | 1151 | break; |
1167 | 1152 | ||
1168 | default: | 1153 | default: |
1169 | port->stats.updunno++; | 1154 | adapter->stats.updunno++; |
1170 | break; | 1155 | break; |
1171 | } | 1156 | } |
1172 | 1157 | ||
@@ -1178,14 +1163,13 @@ netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, | |||
1178 | /* | 1163 | /* |
1179 | * We just consumed one buffer so post a buffer. | 1164 | * We just consumed one buffer so post a buffer. |
1180 | */ | 1165 | */ |
1181 | adapter->stats.post_called++; | ||
1182 | buffer->skb = NULL; | 1166 | buffer->skb = NULL; |
1183 | buffer->state = NETXEN_BUFFER_FREE; | 1167 | buffer->state = NETXEN_BUFFER_FREE; |
1184 | buffer->lro_current_frags = 0; | 1168 | buffer->lro_current_frags = 0; |
1185 | buffer->lro_expected_frags = 0; | 1169 | buffer->lro_expected_frags = 0; |
1186 | 1170 | ||
1187 | port->stats.no_rcv++; | 1171 | adapter->stats.no_rcv++; |
1188 | port->stats.rxbytes += length; | 1172 | adapter->stats.rxbytes += length; |
1189 | } | 1173 | } |
1190 | 1174 | ||
1191 | /* Process Receive status ring */ | 1175 | /* Process Receive status ring */ |
@@ -1226,7 +1210,6 @@ u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max) | |||
1226 | 1210 | ||
1227 | /* update the consumer index in phantom */ | 1211 | /* update the consumer index in phantom */ |
1228 | if (count) { | 1212 | if (count) { |
1229 | adapter->stats.process_rcv++; | ||
1230 | recv_ctx->status_rx_consumer = consumer; | 1213 | recv_ctx->status_rx_consumer = consumer; |
1231 | recv_ctx->status_rx_producer = producer; | 1214 | recv_ctx->status_rx_producer = producer; |
1232 | 1215 | ||
@@ -1249,13 +1232,10 @@ int netxen_process_cmd_ring(unsigned long data) | |||
1249 | int count1 = 0; | 1232 | int count1 = 0; |
1250 | int count2 = 0; | 1233 | int count2 = 0; |
1251 | struct netxen_cmd_buffer *buffer; | 1234 | struct netxen_cmd_buffer *buffer; |
1252 | struct netxen_port *port; /* port #1 */ | ||
1253 | struct netxen_port *nport; | ||
1254 | struct pci_dev *pdev; | 1235 | struct pci_dev *pdev; |
1255 | struct netxen_skb_frag *frag; | 1236 | struct netxen_skb_frag *frag; |
1256 | u32 i; | 1237 | u32 i; |
1257 | struct sk_buff *skb = NULL; | 1238 | struct sk_buff *skb = NULL; |
1258 | int p; | ||
1259 | int done; | 1239 | int done; |
1260 | 1240 | ||
1261 | spin_lock(&adapter->tx_lock); | 1241 | spin_lock(&adapter->tx_lock); |
@@ -1276,7 +1256,6 @@ int netxen_process_cmd_ring(unsigned long data) | |||
1276 | } | 1256 | } |
1277 | 1257 | ||
1278 | adapter->proc_cmd_buf_counter++; | 1258 | adapter->proc_cmd_buf_counter++; |
1279 | adapter->stats.process_xmit++; | ||
1280 | /* | 1259 | /* |
1281 | * Not needed - does not seem to be used anywhere. | 1260 | * Not needed - does not seem to be used anywhere. |
1282 | * adapter->cmd_consumer = consumer; | 1261 | * adapter->cmd_consumer = consumer; |
@@ -1285,8 +1264,7 @@ int netxen_process_cmd_ring(unsigned long data) | |||
1285 | 1264 | ||
1286 | while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) { | 1265 | while ((last_consumer != consumer) && (count1 < MAX_STATUS_HANDLE)) { |
1287 | buffer = &adapter->cmd_buf_arr[last_consumer]; | 1266 | buffer = &adapter->cmd_buf_arr[last_consumer]; |
1288 | port = adapter->port[buffer->port]; | 1267 | pdev = adapter->pdev; |
1289 | pdev = port->pdev; | ||
1290 | frag = &buffer->frag_array[0]; | 1268 | frag = &buffer->frag_array[0]; |
1291 | skb = buffer->skb; | 1269 | skb = buffer->skb; |
1292 | if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) { | 1270 | if (skb && (cmpxchg(&buffer->skb, skb, 0) == skb)) { |
@@ -1299,24 +1277,23 @@ int netxen_process_cmd_ring(unsigned long data) | |||
1299 | PCI_DMA_TODEVICE); | 1277 | PCI_DMA_TODEVICE); |
1300 | } | 1278 | } |
1301 | 1279 | ||
1302 | port->stats.skbfreed++; | 1280 | adapter->stats.skbfreed++; |
1303 | dev_kfree_skb_any(skb); | 1281 | dev_kfree_skb_any(skb); |
1304 | skb = NULL; | 1282 | skb = NULL; |
1305 | } else if (adapter->proc_cmd_buf_counter == 1) { | 1283 | } else if (adapter->proc_cmd_buf_counter == 1) { |
1306 | port->stats.txnullskb++; | 1284 | adapter->stats.txnullskb++; |
1307 | } | 1285 | } |
1308 | if (unlikely(netif_queue_stopped(port->netdev) | 1286 | if (unlikely(netif_queue_stopped(adapter->netdev) |
1309 | && netif_carrier_ok(port->netdev)) | 1287 | && netif_carrier_ok(adapter->netdev)) |
1310 | && ((jiffies - port->netdev->trans_start) > | 1288 | && ((jiffies - adapter->netdev->trans_start) > |
1311 | port->netdev->watchdog_timeo)) { | 1289 | adapter->netdev->watchdog_timeo)) { |
1312 | SCHEDULE_WORK(&port->tx_timeout_task); | 1290 | SCHEDULE_WORK(&adapter->tx_timeout_task); |
1313 | } | 1291 | } |
1314 | 1292 | ||
1315 | last_consumer = get_next_index(last_consumer, | 1293 | last_consumer = get_next_index(last_consumer, |
1316 | adapter->max_tx_desc_count); | 1294 | adapter->max_tx_desc_count); |
1317 | count1++; | 1295 | count1++; |
1318 | } | 1296 | } |
1319 | adapter->stats.noxmitdone += count1; | ||
1320 | 1297 | ||
1321 | count2 = 0; | 1298 | count2 = 0; |
1322 | spin_lock(&adapter->tx_lock); | 1299 | spin_lock(&adapter->tx_lock); |
@@ -1336,13 +1313,10 @@ int netxen_process_cmd_ring(unsigned long data) | |||
1336 | } | 1313 | } |
1337 | } | 1314 | } |
1338 | if (count1 || count2) { | 1315 | if (count1 || count2) { |
1339 | for (p = 0; p < adapter->ahw.max_ports; p++) { | 1316 | if (netif_queue_stopped(adapter->netdev) |
1340 | nport = adapter->port[p]; | 1317 | && (adapter->flags & NETXEN_NETDEV_STATUS)) { |
1341 | if (netif_queue_stopped(nport->netdev) | 1318 | netif_wake_queue(adapter->netdev); |
1342 | && (nport->flags & NETXEN_NETDEV_STATUS)) { | 1319 | adapter->flags &= ~NETXEN_NETDEV_STATUS; |
1343 | netif_wake_queue(nport->netdev); | ||
1344 | nport->flags &= ~NETXEN_NETDEV_STATUS; | ||
1345 | } | ||
1346 | } | 1320 | } |
1347 | } | 1321 | } |
1348 | /* | 1322 | /* |
@@ -1388,7 +1362,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) | |||
1388 | netxen_ctx_msg msg = 0; | 1362 | netxen_ctx_msg msg = 0; |
1389 | dma_addr_t dma; | 1363 | dma_addr_t dma; |
1390 | 1364 | ||
1391 | adapter->stats.post_called++; | ||
1392 | rcv_desc = &recv_ctx->rcv_desc[ringid]; | 1365 | rcv_desc = &recv_ctx->rcv_desc[ringid]; |
1393 | 1366 | ||
1394 | producer = rcv_desc->producer; | 1367 | producer = rcv_desc->producer; |
@@ -1441,8 +1414,6 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) | |||
1441 | if (count) { | 1414 | if (count) { |
1442 | rcv_desc->begin_alloc = index; | 1415 | rcv_desc->begin_alloc = index; |
1443 | rcv_desc->rcv_pending += count; | 1416 | rcv_desc->rcv_pending += count; |
1444 | adapter->stats.lastposted = count; | ||
1445 | adapter->stats.posted += count; | ||
1446 | rcv_desc->producer = producer; | 1417 | rcv_desc->producer = producer; |
1447 | if (rcv_desc->rcv_free >= 32) { | 1418 | if (rcv_desc->rcv_free >= 32) { |
1448 | rcv_desc->rcv_free = 0; | 1419 | rcv_desc->rcv_free = 0; |
@@ -1450,7 +1421,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) | |||
1450 | writel((producer - 1) & | 1421 | writel((producer - 1) & |
1451 | (rcv_desc->max_rx_desc_count - 1), | 1422 | (rcv_desc->max_rx_desc_count - 1), |
1452 | NETXEN_CRB_NORMALIZE(adapter, | 1423 | NETXEN_CRB_NORMALIZE(adapter, |
1453 | recv_crb_registers[0]. | 1424 | recv_crb_registers[ |
1425 | adapter->portnum]. | ||
1454 | rcv_desc_crb[ringid]. | 1426 | rcv_desc_crb[ringid]. |
1455 | crb_rcv_producer_offset)); | 1427 | crb_rcv_producer_offset)); |
1456 | /* | 1428 | /* |
@@ -1463,7 +1435,7 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid) | |||
1463 | ((producer - | 1435 | ((producer - |
1464 | 1) & (rcv_desc-> | 1436 | 1) & (rcv_desc-> |
1465 | max_rx_desc_count - 1))); | 1437 | max_rx_desc_count - 1))); |
1466 | netxen_set_msg_ctxid(msg, 0); | 1438 | netxen_set_msg_ctxid(msg, adapter->portnum); |
1467 | netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid)); | 1439 | netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid)); |
1468 | writel(msg, | 1440 | writel(msg, |
1469 | DB_NORMALIZE(adapter, | 1441 | DB_NORMALIZE(adapter, |
@@ -1485,7 +1457,6 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, | |||
1485 | int count = 0; | 1457 | int count = 0; |
1486 | int index = 0; | 1458 | int index = 0; |
1487 | 1459 | ||
1488 | adapter->stats.post_called++; | ||
1489 | rcv_desc = &recv_ctx->rcv_desc[ringid]; | 1460 | rcv_desc = &recv_ctx->rcv_desc[ringid]; |
1490 | 1461 | ||
1491 | producer = rcv_desc->producer; | 1462 | producer = rcv_desc->producer; |
@@ -1532,8 +1503,6 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, | |||
1532 | if (count) { | 1503 | if (count) { |
1533 | rcv_desc->begin_alloc = index; | 1504 | rcv_desc->begin_alloc = index; |
1534 | rcv_desc->rcv_pending += count; | 1505 | rcv_desc->rcv_pending += count; |
1535 | adapter->stats.lastposted = count; | ||
1536 | adapter->stats.posted += count; | ||
1537 | rcv_desc->producer = producer; | 1506 | rcv_desc->producer = producer; |
1538 | if (rcv_desc->rcv_free >= 32) { | 1507 | if (rcv_desc->rcv_free >= 32) { |
1539 | rcv_desc->rcv_free = 0; | 1508 | rcv_desc->rcv_free = 0; |
@@ -1541,7 +1510,8 @@ void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter, uint32_t ctx, | |||
1541 | writel((producer - 1) & | 1510 | writel((producer - 1) & |
1542 | (rcv_desc->max_rx_desc_count - 1), | 1511 | (rcv_desc->max_rx_desc_count - 1), |
1543 | NETXEN_CRB_NORMALIZE(adapter, | 1512 | NETXEN_CRB_NORMALIZE(adapter, |
1544 | recv_crb_registers[0]. | 1513 | recv_crb_registers[ |
1514 | adapter->portnum]. | ||
1545 | rcv_desc_crb[ringid]. | 1515 | rcv_desc_crb[ringid]. |
1546 | crb_rcv_producer_offset)); | 1516 | crb_rcv_producer_offset)); |
1547 | wmb(); | 1517 | wmb(); |
@@ -1562,13 +1532,7 @@ int netxen_nic_tx_has_work(struct netxen_adapter *adapter) | |||
1562 | 1532 | ||
1563 | void netxen_nic_clear_stats(struct netxen_adapter *adapter) | 1533 | void netxen_nic_clear_stats(struct netxen_adapter *adapter) |
1564 | { | 1534 | { |
1565 | struct netxen_port *port; | ||
1566 | int port_num; | ||
1567 | |||
1568 | memset(&adapter->stats, 0, sizeof(adapter->stats)); | 1535 | memset(&adapter->stats, 0, sizeof(adapter->stats)); |
1569 | for (port_num = 0; port_num < adapter->ahw.max_ports; port_num++) { | 1536 | return; |
1570 | port = adapter->port[port_num]; | ||
1571 | memset(&port->stats, 0, sizeof(port->stats)); | ||
1572 | } | ||
1573 | } | 1537 | } |
1574 | 1538 | ||
diff --git a/drivers/net/netxen/netxen_nic_isr.c b/drivers/net/netxen/netxen_nic_isr.c index be366e48007c..b213b062eb56 100644 --- a/drivers/net/netxen/netxen_nic_isr.c +++ b/drivers/net/netxen/netxen_nic_isr.c | |||
@@ -6,12 +6,12 @@ | |||
6 | * modify it under the terms of the GNU General Public License | 6 | * modify it under the terms of the GNU General Public License |
7 | * as published by the Free Software Foundation; either version 2 | 7 | * as published by the Free Software Foundation; either version 2 |
8 | * of the License, or (at your option) any later version. | 8 | * of the License, or (at your option) any later version. |
9 | * | 9 | * |
10 | * This program is distributed in the hope that it will be useful, but | 10 | * This program is distributed in the hope that it will be useful, but |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
14 | * | 14 | * |
15 | * You should have received a copy of the GNU General Public License | 15 | * You should have received a copy of the GNU General Public License |
16 | * along with this program; if not, write to the Free Software | 16 | * along with this program; if not, write to the Free Software |
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, | 17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
@@ -40,35 +40,35 @@ | |||
40 | */ | 40 | */ |
41 | struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) | 41 | struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev) |
42 | { | 42 | { |
43 | struct netxen_port *port = netdev_priv(netdev); | 43 | struct netxen_adapter *adapter = netdev_priv(netdev); |
44 | struct net_device_stats *stats = &port->net_stats; | 44 | struct net_device_stats *stats = &adapter->net_stats; |
45 | 45 | ||
46 | memset(stats, 0, sizeof(*stats)); | 46 | memset(stats, 0, sizeof(*stats)); |
47 | 47 | ||
48 | /* total packets received */ | 48 | /* total packets received */ |
49 | stats->rx_packets = port->stats.no_rcv; | 49 | stats->rx_packets = adapter->stats.no_rcv; |
50 | /* total packets transmitted */ | 50 | /* total packets transmitted */ |
51 | stats->tx_packets = port->stats.xmitedframes + port->stats.xmitfinished; | 51 | stats->tx_packets = adapter->stats.xmitedframes + |
52 | adapter->stats.xmitfinished; | ||
52 | /* total bytes received */ | 53 | /* total bytes received */ |
53 | stats->rx_bytes = port->stats.rxbytes; | 54 | stats->rx_bytes = adapter->stats.rxbytes; |
54 | /* total bytes transmitted */ | 55 | /* total bytes transmitted */ |
55 | stats->tx_bytes = port->stats.txbytes; | 56 | stats->tx_bytes = adapter->stats.txbytes; |
56 | /* bad packets received */ | 57 | /* bad packets received */ |
57 | stats->rx_errors = port->stats.rcvdbadskb; | 58 | stats->rx_errors = adapter->stats.rcvdbadskb; |
58 | /* packet transmit problems */ | 59 | /* packet transmit problems */ |
59 | stats->tx_errors = port->stats.nocmddescriptor; | 60 | stats->tx_errors = adapter->stats.nocmddescriptor; |
60 | /* no space in linux buffers */ | 61 | /* no space in linux buffers */ |
61 | stats->rx_dropped = port->stats.updropped; | 62 | stats->rx_dropped = adapter->stats.updropped; |
62 | /* no space available in linux */ | 63 | /* no space available in linux */ |
63 | stats->tx_dropped = port->stats.txdropped; | 64 | stats->tx_dropped = adapter->stats.txdropped; |
64 | 65 | ||
65 | return stats; | 66 | return stats; |
66 | } | 67 | } |
67 | 68 | ||
68 | void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno, | 69 | void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 link) |
69 | u32 link) | ||
70 | { | 70 | { |
71 | struct net_device *netdev = (adapter->port[portno])->netdev; | 71 | struct net_device *netdev = adapter->netdev; |
72 | 72 | ||
73 | if (link) | 73 | if (link) |
74 | netif_carrier_on(netdev); | 74 | netif_carrier_on(netdev); |
@@ -76,15 +76,13 @@ void netxen_indicate_link_status(struct netxen_adapter *adapter, u32 portno, | |||
76 | netif_carrier_off(netdev); | 76 | netif_carrier_off(netdev); |
77 | } | 77 | } |
78 | 78 | ||
79 | void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno, | 79 | void netxen_handle_port_int(struct netxen_adapter *adapter, u32 enable) |
80 | u32 enable) | ||
81 | { | 80 | { |
82 | __u32 int_src; | 81 | __u32 int_src; |
83 | struct netxen_port *port; | ||
84 | 82 | ||
85 | /* This should clear the interrupt source */ | 83 | /* This should clear the interrupt source */ |
86 | if (adapter->phy_read) | 84 | if (adapter->phy_read) |
87 | adapter->phy_read(adapter, portno, | 85 | adapter->phy_read(adapter, |
88 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, | 86 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, |
89 | &int_src); | 87 | &int_src); |
90 | if (int_src == 0) { | 88 | if (int_src == 0) { |
@@ -92,9 +90,7 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno, | |||
92 | return; | 90 | return; |
93 | } | 91 | } |
94 | if (adapter->disable_phy_interrupts) | 92 | if (adapter->disable_phy_interrupts) |
95 | adapter->disable_phy_interrupts(adapter, portno); | 93 | adapter->disable_phy_interrupts(adapter); |
96 | |||
97 | port = adapter->port[portno]; | ||
98 | 94 | ||
99 | if (netxen_get_phy_int_jabber(int_src)) | 95 | if (netxen_get_phy_int_jabber(int_src)) |
100 | DPRINTK(INFO, "Jabber interrupt \n"); | 96 | DPRINTK(INFO, "Jabber interrupt \n"); |
@@ -115,64 +111,57 @@ void netxen_handle_port_int(struct netxen_adapter *adapter, u32 portno, | |||
115 | DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n"); | 111 | DPRINTK(INFO, "SPEED CHANGED OR LINK STATUS CHANGED \n"); |
116 | 112 | ||
117 | if (adapter->phy_read | 113 | if (adapter->phy_read |
118 | && adapter->phy_read(adapter, portno, | 114 | && adapter->phy_read(adapter, |
119 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, | 115 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
120 | &status) == 0) { | 116 | &status) == 0) { |
121 | if (netxen_get_phy_int_link_status_changed(int_src)) { | 117 | if (netxen_get_phy_int_link_status_changed(int_src)) { |
122 | if (netxen_get_phy_link(status)) { | 118 | if (netxen_get_phy_link(status)) { |
123 | netxen_niu_gbe_init_port(adapter, | 119 | printk(KERN_INFO "%s: %s Link UP\n", |
124 | portno); | ||
125 | printk("%s: %s Link UP\n", | ||
126 | netxen_nic_driver_name, | 120 | netxen_nic_driver_name, |
127 | port->netdev->name); | 121 | adapter->netdev->name); |
128 | 122 | ||
129 | } else { | 123 | } else { |
130 | printk("%s: %s Link DOWN\n", | 124 | printk(KERN_INFO "%s: %s Link DOWN\n", |
131 | netxen_nic_driver_name, | 125 | netxen_nic_driver_name, |
132 | port->netdev->name); | 126 | adapter->netdev->name); |
133 | } | 127 | } |
134 | netxen_indicate_link_status(adapter, portno, | 128 | netxen_indicate_link_status(adapter, |
135 | netxen_get_phy_link | 129 | netxen_get_phy_link |
136 | (status)); | 130 | (status)); |
137 | } | 131 | } |
138 | } | 132 | } |
139 | } | 133 | } |
140 | if (adapter->enable_phy_interrupts) | 134 | if (adapter->enable_phy_interrupts) |
141 | adapter->enable_phy_interrupts(adapter, portno); | 135 | adapter->enable_phy_interrupts(adapter); |
142 | } | 136 | } |
143 | 137 | ||
144 | void netxen_nic_isr_other(struct netxen_adapter *adapter) | 138 | void netxen_nic_isr_other(struct netxen_adapter *adapter) |
145 | { | 139 | { |
146 | u32 portno; | 140 | int portno = adapter->portnum; |
147 | u32 val, linkup, qg_linksup; | 141 | u32 val, linkup, qg_linksup; |
148 | 142 | ||
149 | /* verify the offset */ | 143 | /* verify the offset */ |
150 | val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); | 144 | val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); |
145 | val = val >> physical_port[adapter->portnum]; | ||
151 | if (val == adapter->ahw.qg_linksup) | 146 | if (val == adapter->ahw.qg_linksup) |
152 | return; | 147 | return; |
153 | 148 | ||
154 | qg_linksup = adapter->ahw.qg_linksup; | 149 | qg_linksup = adapter->ahw.qg_linksup; |
155 | adapter->ahw.qg_linksup = val; | 150 | adapter->ahw.qg_linksup = val; |
156 | DPRINTK(INFO, "link update 0x%08x\n", val); | 151 | DPRINTK(INFO, "link update 0x%08x\n", val); |
157 | for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) { | ||
158 | linkup = val & 1; | ||
159 | if (linkup != (qg_linksup & 1)) { | ||
160 | printk(KERN_INFO "%s: %s PORT %d link %s\n", | ||
161 | adapter->port[portno]->netdev->name, | ||
162 | netxen_nic_driver_name, portno, | ||
163 | ((linkup == 0) ? "down" : "up")); | ||
164 | netxen_indicate_link_status(adapter, portno, linkup); | ||
165 | if (linkup) | ||
166 | netxen_nic_set_link_parameters(adapter-> | ||
167 | port[portno]); | ||
168 | 152 | ||
169 | } | 153 | linkup = val & 1; |
170 | val = val >> 1; | ||
171 | qg_linksup = qg_linksup >> 1; | ||
172 | } | ||
173 | 154 | ||
174 | adapter->stats.otherints++; | 155 | if (linkup != (qg_linksup & 1)) { |
156 | printk(KERN_INFO "%s: %s PORT %d link %s\n", | ||
157 | adapter->netdev->name, | ||
158 | netxen_nic_driver_name, portno, | ||
159 | ((linkup == 0) ? "down" : "up")); | ||
160 | netxen_indicate_link_status(adapter, linkup); | ||
161 | if (linkup) | ||
162 | netxen_nic_set_link_parameters(adapter); | ||
175 | 163 | ||
164 | } | ||
176 | } | 165 | } |
177 | 166 | ||
178 | void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter) | 167 | void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter) |
@@ -182,26 +171,28 @@ void netxen_nic_gbe_handle_phy_intr(struct netxen_adapter *adapter) | |||
182 | 171 | ||
183 | void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter) | 172 | void netxen_nic_xgbe_handle_phy_intr(struct netxen_adapter *adapter) |
184 | { | 173 | { |
185 | struct net_device *netdev = adapter->port[0]->netdev; | 174 | struct net_device *netdev = adapter->netdev; |
186 | u32 val; | 175 | u32 val, val1; |
187 | 176 | ||
188 | /* WINDOW = 1 */ | 177 | /* WINDOW = 1 */ |
189 | val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); | 178 | val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_XG_STATE)); |
179 | val >>= (physical_port[adapter->portnum] * 8); | ||
180 | val1 = val & 0xff; | ||
190 | 181 | ||
191 | if (adapter->ahw.xg_linkup == 1 && val != XG_LINK_UP) { | 182 | if (adapter->ahw.xg_linkup == 1 && val1 != XG_LINK_UP) { |
192 | printk(KERN_INFO "%s: %s NIC Link is down\n", | 183 | printk(KERN_INFO "%s: %s NIC Link is down\n", |
193 | netxen_nic_driver_name, netdev->name); | 184 | netxen_nic_driver_name, netdev->name); |
194 | adapter->ahw.xg_linkup = 0; | 185 | adapter->ahw.xg_linkup = 0; |
195 | /* read twice to clear sticky bits */ | 186 | /* read twice to clear sticky bits */ |
196 | /* WINDOW = 0 */ | 187 | /* WINDOW = 0 */ |
197 | netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val); | 188 | netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1); |
198 | netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val); | 189 | netxen_nic_read_w0(adapter, NETXEN_NIU_XG_STATUS, &val1); |
199 | 190 | ||
200 | if ((val & 0xffb) != 0xffb) { | 191 | if ((val & 0xffb) != 0xffb) { |
201 | printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n", | 192 | printk(KERN_INFO "%s ISR: Sync/Align BAD: 0x%08x\n", |
202 | netxen_nic_driver_name, val); | 193 | netxen_nic_driver_name, val1); |
203 | } | 194 | } |
204 | } else if (adapter->ahw.xg_linkup == 0 && val == XG_LINK_UP) { | 195 | } else if (adapter->ahw.xg_linkup == 0 && val1 == XG_LINK_UP) { |
205 | printk(KERN_INFO "%s: %s NIC Link is up\n", | 196 | printk(KERN_INFO "%s: %s NIC Link is up\n", |
206 | netxen_nic_driver_name, netdev->name); | 197 | netxen_nic_driver_name, netdev->name); |
207 | adapter->ahw.xg_linkup = 1; | 198 | adapter->ahw.xg_linkup = 1; |
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index ab25c225a07e..4e32bb678ea9 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c | |||
@@ -36,7 +36,6 @@ | |||
36 | #include "netxen_nic_hw.h" | 36 | #include "netxen_nic_hw.h" |
37 | 37 | ||
38 | #include "netxen_nic.h" | 38 | #include "netxen_nic.h" |
39 | #define DEFINE_GLOBAL_RECV_CRB | ||
40 | #include "netxen_nic_phan_reg.h" | 39 | #include "netxen_nic_phan_reg.h" |
41 | 40 | ||
42 | #include <linux/dma-mapping.h> | 41 | #include <linux/dma-mapping.h> |
@@ -77,6 +76,8 @@ static void netxen_nic_poll_controller(struct net_device *netdev); | |||
77 | #endif | 76 | #endif |
78 | static irqreturn_t netxen_intr(int irq, void *data); | 77 | static irqreturn_t netxen_intr(int irq, void *data); |
79 | 78 | ||
79 | int physical_port[] = {0, 1, 2, 3}; | ||
80 | |||
80 | /* PCI Device ID Table */ | 81 | /* PCI Device ID Table */ |
81 | static struct pci_device_id netxen_pci_tbl[] __devinitdata = { | 82 | static struct pci_device_id netxen_pci_tbl[] __devinitdata = { |
82 | {PCI_DEVICE(0x4040, 0x0001)}, | 83 | {PCI_DEVICE(0x4040, 0x0001)}, |
@@ -94,6 +95,67 @@ MODULE_DEVICE_TABLE(pci, netxen_pci_tbl); | |||
94 | struct workqueue_struct *netxen_workq; | 95 | struct workqueue_struct *netxen_workq; |
95 | static void netxen_watchdog(unsigned long); | 96 | static void netxen_watchdog(unsigned long); |
96 | 97 | ||
98 | static inline void netxen_nic_update_cmd_producer(struct netxen_adapter *adapter, | ||
99 | uint32_t crb_producer) | ||
100 | { | ||
101 | switch (adapter->portnum) { | ||
102 | case 0: | ||
103 | writel(crb_producer, NETXEN_CRB_NORMALIZE | ||
104 | (adapter, CRB_CMD_PRODUCER_OFFSET)); | ||
105 | return; | ||
106 | case 1: | ||
107 | writel(crb_producer, NETXEN_CRB_NORMALIZE | ||
108 | (adapter, CRB_CMD_PRODUCER_OFFSET_1)); | ||
109 | return; | ||
110 | case 2: | ||
111 | writel(crb_producer, NETXEN_CRB_NORMALIZE | ||
112 | (adapter, CRB_CMD_PRODUCER_OFFSET_2)); | ||
113 | return; | ||
114 | case 3: | ||
115 | writel(crb_producer, NETXEN_CRB_NORMALIZE | ||
116 | (adapter, CRB_CMD_PRODUCER_OFFSET_3)); | ||
117 | return; | ||
118 | default: | ||
119 | printk(KERN_WARNING "We tried to update " | ||
120 | "CRB_CMD_PRODUCER_OFFSET for invalid " | ||
121 | "PCI function id %d\n", | ||
122 | adapter->portnum); | ||
123 | return; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static inline void netxen_nic_update_cmd_consumer(struct netxen_adapter *adapter, | ||
128 | u32 crb_consumer) | ||
129 | { | ||
130 | switch (adapter->portnum) { | ||
131 | case 0: | ||
132 | writel(crb_consumer, NETXEN_CRB_NORMALIZE | ||
133 | (adapter, CRB_CMD_CONSUMER_OFFSET)); | ||
134 | return; | ||
135 | case 1: | ||
136 | writel(crb_consumer, NETXEN_CRB_NORMALIZE | ||
137 | (adapter, CRB_CMD_CONSUMER_OFFSET_1)); | ||
138 | return; | ||
139 | case 2: | ||
140 | writel(crb_consumer, NETXEN_CRB_NORMALIZE | ||
141 | (adapter, CRB_CMD_CONSUMER_OFFSET_2)); | ||
142 | return; | ||
143 | case 3: | ||
144 | writel(crb_consumer, NETXEN_CRB_NORMALIZE | ||
145 | (adapter, CRB_CMD_CONSUMER_OFFSET_3)); | ||
146 | return; | ||
147 | default: | ||
148 | printk(KERN_WARNING "We tried to update " | ||
149 | "CRB_CMD_PRODUCER_OFFSET for invalid " | ||
150 | "PCI function id %d\n", | ||
151 | adapter->portnum); | ||
152 | return; | ||
153 | } | ||
154 | } | ||
155 | |||
156 | #define ADAPTER_LIST_SIZE 12 | ||
157 | int netxen_cards_found; | ||
158 | |||
97 | /* | 159 | /* |
98 | * netxen_nic_probe() | 160 | * netxen_nic_probe() |
99 | * | 161 | * |
@@ -111,26 +173,30 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
111 | { | 173 | { |
112 | struct net_device *netdev = NULL; | 174 | struct net_device *netdev = NULL; |
113 | struct netxen_adapter *adapter = NULL; | 175 | struct netxen_adapter *adapter = NULL; |
114 | struct netxen_port *port = NULL; | ||
115 | void __iomem *mem_ptr0 = NULL; | 176 | void __iomem *mem_ptr0 = NULL; |
116 | void __iomem *mem_ptr1 = NULL; | 177 | void __iomem *mem_ptr1 = NULL; |
117 | void __iomem *mem_ptr2 = NULL; | 178 | void __iomem *mem_ptr2 = NULL; |
179 | unsigned long first_page_group_end; | ||
180 | unsigned long first_page_group_start; | ||
181 | |||
118 | 182 | ||
119 | u8 __iomem *db_ptr = NULL; | 183 | u8 __iomem *db_ptr = NULL; |
120 | unsigned long mem_base, mem_len, db_base, db_len; | 184 | unsigned long mem_base, mem_len, db_base, db_len; |
121 | int pci_using_dac, i, err; | 185 | int pci_using_dac, i = 0, err; |
122 | int ring; | 186 | int ring; |
123 | struct netxen_recv_context *recv_ctx = NULL; | 187 | struct netxen_recv_context *recv_ctx = NULL; |
124 | struct netxen_rcv_desc_ctx *rcv_desc = NULL; | 188 | struct netxen_rcv_desc_ctx *rcv_desc = NULL; |
125 | struct netxen_cmd_buffer *cmd_buf_arr = NULL; | 189 | struct netxen_cmd_buffer *cmd_buf_arr = NULL; |
126 | u64 mac_addr[FLASH_NUM_PORTS + 1]; | 190 | u64 mac_addr[FLASH_NUM_PORTS + 1]; |
127 | int valid_mac = 0; | 191 | int valid_mac = 0; |
192 | u32 val; | ||
193 | int pci_func_id = PCI_FUNC(pdev->devfn); | ||
128 | 194 | ||
129 | printk(KERN_INFO "%s \n", netxen_nic_driver_string); | 195 | printk(KERN_INFO "%s \n", netxen_nic_driver_string); |
130 | /* In current scheme, we use only PCI function 0 */ | 196 | |
131 | if (PCI_FUNC(pdev->devfn) != 0) { | 197 | if (pdev->class != 0x020000) { |
132 | DPRINTK(ERR, "NetXen function %d will not be enabled.\n", | 198 | printk(KERN_ERR"NetXen function %d, class %x will not" |
133 | PCI_FUNC(pdev->devfn)); | 199 | "be enabled.\n",pci_func_id, pdev->class); |
134 | return -ENODEV; | 200 | return -ENODEV; |
135 | } | 201 | } |
136 | if ((err = pci_enable_device(pdev))) | 202 | if ((err = pci_enable_device(pdev))) |
@@ -157,18 +223,52 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
157 | pci_using_dac = 0; | 223 | pci_using_dac = 0; |
158 | } | 224 | } |
159 | 225 | ||
226 | |||
227 | netdev = alloc_etherdev(sizeof(struct netxen_adapter)); | ||
228 | if(!netdev) { | ||
229 | printk(KERN_ERR"%s: Failed to allocate memory for the " | ||
230 | "device block.Check system memory resource" | ||
231 | " usage.\n", netxen_nic_driver_name); | ||
232 | goto err_out_free_res; | ||
233 | } | ||
234 | |||
235 | SET_MODULE_OWNER(netdev); | ||
236 | SET_NETDEV_DEV(netdev, &pdev->dev); | ||
237 | |||
238 | adapter = netdev->priv; | ||
239 | memset(adapter, 0 , sizeof(struct netxen_adapter)); | ||
240 | |||
241 | adapter->ahw.pdev = pdev; | ||
242 | adapter->ahw.pci_func = pci_func_id; | ||
243 | spin_lock_init(&adapter->tx_lock); | ||
244 | spin_lock_init(&adapter->lock); | ||
245 | |||
160 | /* remap phys address */ | 246 | /* remap phys address */ |
161 | mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ | 247 | mem_base = pci_resource_start(pdev, 0); /* 0 is for BAR 0 */ |
162 | mem_len = pci_resource_len(pdev, 0); | 248 | mem_len = pci_resource_len(pdev, 0); |
163 | 249 | ||
164 | /* 128 Meg of memory */ | 250 | /* 128 Meg of memory */ |
165 | mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); | 251 | if (mem_len == NETXEN_PCI_128MB_SIZE) { |
166 | mem_ptr1 = | 252 | mem_ptr0 = ioremap(mem_base, FIRST_PAGE_GROUP_SIZE); |
167 | ioremap(mem_base + SECOND_PAGE_GROUP_START, SECOND_PAGE_GROUP_SIZE); | 253 | mem_ptr1 = ioremap(mem_base + SECOND_PAGE_GROUP_START, |
168 | mem_ptr2 = | 254 | SECOND_PAGE_GROUP_SIZE); |
169 | ioremap(mem_base + THIRD_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); | 255 | mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START, |
256 | THIRD_PAGE_GROUP_SIZE); | ||
257 | first_page_group_start = FIRST_PAGE_GROUP_START; | ||
258 | first_page_group_end = FIRST_PAGE_GROUP_END; | ||
259 | } else if (mem_len == NETXEN_PCI_32MB_SIZE) { | ||
260 | mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE); | ||
261 | mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START - | ||
262 | SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE); | ||
263 | first_page_group_start = 0; | ||
264 | first_page_group_end = 0; | ||
265 | } else { | ||
266 | err = -EIO; | ||
267 | goto err_out_free_netdev; | ||
268 | } | ||
170 | 269 | ||
171 | if ((mem_ptr0 == 0UL) || (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) { | 270 | if (((mem_ptr0 == 0UL) && (mem_len == NETXEN_PCI_128MB_SIZE)) || |
271 | (mem_ptr1 == 0UL) || (mem_ptr2 == 0UL)) { | ||
172 | DPRINTK(ERR, | 272 | DPRINTK(ERR, |
173 | "Cannot remap adapter memory aborting.:" | 273 | "Cannot remap adapter memory aborting.:" |
174 | "0 -> %p, 1 -> %p, 2 -> %p\n", | 274 | "0 -> %p, 1 -> %p, 2 -> %p\n", |
@@ -198,30 +298,87 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
198 | } | 298 | } |
199 | DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr); | 299 | DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr); |
200 | 300 | ||
201 | /* | 301 | adapter->ahw.pci_base0 = mem_ptr0; |
202 | * Allocate a adapter structure which will manage all the initialization | 302 | adapter->ahw.first_page_group_start = first_page_group_start; |
203 | * as well as the common resources for all ports... | 303 | adapter->ahw.first_page_group_end = first_page_group_end; |
204 | * all the ports will have pointer to this adapter as well as Adapter | 304 | adapter->ahw.pci_base1 = mem_ptr1; |
205 | * will have pointers of all the ports structures. | 305 | adapter->ahw.pci_base2 = mem_ptr2; |
206 | */ | 306 | adapter->ahw.db_base = db_ptr; |
307 | adapter->ahw.db_len = db_len; | ||
207 | 308 | ||
208 | /* One adapter structure for all 4 ports.... */ | 309 | adapter->netdev = netdev; |
209 | adapter = kzalloc(sizeof(struct netxen_adapter), GFP_KERNEL); | 310 | adapter->pdev = pdev; |
210 | if (adapter == NULL) { | 311 | adapter->portnum = pci_func_id; |
211 | printk(KERN_ERR "%s: Could not allocate adapter memory:%d\n", | 312 | |
212 | netxen_nic_driver_name, | 313 | netdev->open = netxen_nic_open; |
213 | (int)sizeof(struct netxen_adapter)); | 314 | netdev->stop = netxen_nic_close; |
214 | err = -ENOMEM; | 315 | netdev->hard_start_xmit = netxen_nic_xmit_frame; |
215 | goto err_out_dbunmap; | 316 | netdev->get_stats = netxen_nic_get_stats; |
216 | } | 317 | netdev->set_multicast_list = netxen_nic_set_multi; |
318 | netdev->set_mac_address = netxen_nic_set_mac; | ||
319 | netdev->change_mtu = netxen_nic_change_mtu; | ||
320 | netdev->tx_timeout = netxen_tx_timeout; | ||
321 | netdev->watchdog_timeo = HZ; | ||
322 | |||
323 | netxen_nic_change_mtu(netdev, netdev->mtu); | ||
324 | |||
325 | SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); | ||
326 | netdev->poll = netxen_nic_poll; | ||
327 | netdev->weight = NETXEN_NETDEV_WEIGHT; | ||
328 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
329 | netdev->poll_controller = netxen_nic_poll_controller; | ||
330 | #endif | ||
331 | /* ScatterGather support */ | ||
332 | netdev->features = NETIF_F_SG; | ||
333 | netdev->features |= NETIF_F_IP_CSUM; | ||
334 | netdev->features |= NETIF_F_TSO; | ||
335 | |||
336 | if (pci_using_dac) | ||
337 | netdev->features |= NETIF_F_HIGHDMA; | ||
338 | |||
339 | if (pci_enable_msi(pdev)) { | ||
340 | adapter->flags &= ~NETXEN_NIC_MSI_ENABLED; | ||
341 | printk(KERN_WARNING "%s: unable to allocate MSI interrupt" | ||
342 | " error\n", netxen_nic_driver_name); | ||
343 | } else | ||
344 | adapter->flags |= NETXEN_NIC_MSI_ENABLED; | ||
345 | |||
346 | netdev->irq = pdev->irq; | ||
347 | INIT_WORK(&adapter->tx_timeout_task, netxen_tx_timeout_task); | ||
217 | 348 | ||
218 | adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS; | 349 | /* |
219 | adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS; | 350 | * Set the CRB window to invalid. If any register in window 0 is |
351 | * accessed it should set the window to 0 and then reset it to 1. | ||
352 | */ | ||
353 | adapter->curr_window = 255; | ||
354 | |||
355 | /* initialize the adapter */ | ||
356 | netxen_initialize_adapter_hw(adapter); | ||
357 | |||
358 | #ifdef CONFIG_PPC | ||
359 | if ((adapter->ahw.boardcfg.board_type == | ||
360 | NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) && | ||
361 | (pci_func_id == 2)) | ||
362 | goto err_out_free_adapter; | ||
363 | #endif /* CONFIG_PPC */ | ||
364 | |||
365 | /* | ||
366 | * Adapter in our case is quad port so initialize it before | ||
367 | * initializing the ports | ||
368 | */ | ||
369 | |||
370 | netxen_initialize_adapter_ops(adapter); | ||
371 | |||
372 | adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST; | ||
373 | if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB35_4G) || | ||
374 | (adapter->ahw.boardcfg.board_type == | ||
375 | NETXEN_BRDTYPE_P2_SB31_2G)) | ||
376 | adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G; | ||
377 | else | ||
378 | adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS; | ||
220 | adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS; | 379 | adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS; |
221 | adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS; | 380 | adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS; |
222 | 381 | ||
223 | pci_set_drvdata(pdev, adapter); | ||
224 | |||
225 | cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE); | 382 | cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE); |
226 | if (cmd_buf_arr == NULL) { | 383 | if (cmd_buf_arr == NULL) { |
227 | printk(KERN_ERR | 384 | printk(KERN_ERR |
@@ -231,6 +388,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
231 | goto err_out_free_adapter; | 388 | goto err_out_free_adapter; |
232 | } | 389 | } |
233 | memset(cmd_buf_arr, 0, TX_RINGSIZE); | 390 | memset(cmd_buf_arr, 0, TX_RINGSIZE); |
391 | adapter->cmd_buf_arr = cmd_buf_arr; | ||
234 | 392 | ||
235 | for (i = 0; i < MAX_RCV_CTX; ++i) { | 393 | for (i = 0; i < MAX_RCV_CTX; ++i) { |
236 | recv_ctx = &adapter->recv_ctx[i]; | 394 | recv_ctx = &adapter->recv_ctx[i]; |
@@ -278,33 +436,20 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
278 | 436 | ||
279 | } | 437 | } |
280 | 438 | ||
281 | adapter->cmd_buf_arr = cmd_buf_arr; | ||
282 | adapter->ahw.pci_base0 = mem_ptr0; | ||
283 | adapter->ahw.pci_base1 = mem_ptr1; | ||
284 | adapter->ahw.pci_base2 = mem_ptr2; | ||
285 | adapter->ahw.db_base = db_ptr; | ||
286 | adapter->ahw.db_len = db_len; | ||
287 | spin_lock_init(&adapter->tx_lock); | ||
288 | spin_lock_init(&adapter->lock); | ||
289 | netxen_initialize_adapter_sw(adapter); /* initialize the buffers in adapter */ | 439 | netxen_initialize_adapter_sw(adapter); /* initialize the buffers in adapter */ |
290 | #ifdef CONFIG_IA64 | ||
291 | netxen_pinit_from_rom(adapter, 0); | ||
292 | udelay(500); | ||
293 | netxen_load_firmware(adapter); | ||
294 | #endif | ||
295 | 440 | ||
296 | /* | 441 | /* Mezz cards have PCI function 0,2,3 enabled */ |
297 | * Set the CRB window to invalid. If any register in window 0 is | 442 | if ((adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) |
298 | * accessed it should set the window to 0 and then reset it to 1. | 443 | && (pci_func_id >= 2)) |
299 | */ | 444 | adapter->portnum = pci_func_id - 2; |
300 | adapter->curr_window = 255; | ||
301 | /* | ||
302 | * Adapter in our case is quad port so initialize it before | ||
303 | * initializing the ports | ||
304 | */ | ||
305 | netxen_initialize_adapter_hw(adapter); /* initialize the adapter */ | ||
306 | 445 | ||
307 | netxen_initialize_adapter_ops(adapter); | 446 | #ifdef CONFIG_IA64 |
447 | if(adapter->portnum == 0) { | ||
448 | netxen_pinit_from_rom(adapter, 0); | ||
449 | udelay(500); | ||
450 | netxen_load_firmware(adapter); | ||
451 | } | ||
452 | #endif | ||
308 | 453 | ||
309 | init_timer(&adapter->watchdog_timer); | 454 | init_timer(&adapter->watchdog_timer); |
310 | adapter->ahw.xg_linkup = 0; | 455 | adapter->ahw.xg_linkup = 0; |
@@ -315,12 +460,12 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
315 | adapter->proc_cmd_buf_counter = 0; | 460 | adapter->proc_cmd_buf_counter = 0; |
316 | adapter->ahw.revision_id = nx_p2_id; | 461 | adapter->ahw.revision_id = nx_p2_id; |
317 | 462 | ||
318 | if (pci_enable_msi(pdev)) { | 463 | /* make sure Window == 1 */ |
319 | adapter->flags &= ~NETXEN_NIC_MSI_ENABLED; | 464 | netxen_nic_pci_change_crbwindow(adapter, 1); |
320 | printk(KERN_WARNING "%s: unable to allocate MSI interrupt" | 465 | |
321 | " error\n", netxen_nic_driver_name); | 466 | netxen_nic_update_cmd_producer(adapter, 0); |
322 | } else | 467 | netxen_nic_update_cmd_consumer(adapter, 0); |
323 | adapter->flags |= NETXEN_NIC_MSI_ENABLED; | 468 | writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO)); |
324 | 469 | ||
325 | if (netxen_is_flash_supported(adapter) == 0 && | 470 | if (netxen_is_flash_supported(adapter) == 0 && |
326 | netxen_get_flash_mac_addr(adapter, mac_addr) == 0) | 471 | netxen_get_flash_mac_addr(adapter, mac_addr) == 0) |
@@ -328,153 +473,118 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
328 | else | 473 | else |
329 | valid_mac = 0; | 474 | valid_mac = 0; |
330 | 475 | ||
331 | /* | 476 | if (valid_mac) { |
332 | * Initialize all the CRB registers here. | 477 | unsigned char *p = (unsigned char *)&mac_addr[adapter->portnum]; |
333 | */ | 478 | netdev->dev_addr[0] = *(p + 5); |
334 | writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET)); | 479 | netdev->dev_addr[1] = *(p + 4); |
335 | writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_CONSUMER_OFFSET)); | 480 | netdev->dev_addr[2] = *(p + 3); |
336 | writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO)); | 481 | netdev->dev_addr[3] = *(p + 2); |
337 | 482 | netdev->dev_addr[4] = *(p + 1); | |
338 | /* do this before waking up pegs so that we have valid dummy dma addr */ | 483 | netdev->dev_addr[5] = *(p + 0); |
339 | err = netxen_initialize_adapter_offload(adapter); | 484 | |
340 | if (err) { | 485 | memcpy(netdev->perm_addr, netdev->dev_addr, |
341 | goto err_out_free_dev; | 486 | netdev->addr_len); |
487 | if (!is_valid_ether_addr(netdev->perm_addr)) { | ||
488 | printk(KERN_ERR "%s: Bad MAC address " | ||
489 | "%02x:%02x:%02x:%02x:%02x:%02x.\n", | ||
490 | netxen_nic_driver_name, | ||
491 | netdev->dev_addr[0], | ||
492 | netdev->dev_addr[1], | ||
493 | netdev->dev_addr[2], | ||
494 | netdev->dev_addr[3], | ||
495 | netdev->dev_addr[4], | ||
496 | netdev->dev_addr[5]); | ||
497 | } else { | ||
498 | if (adapter->macaddr_set) | ||
499 | adapter->macaddr_set(adapter, | ||
500 | netdev->dev_addr); | ||
501 | } | ||
342 | } | 502 | } |
343 | 503 | ||
344 | /* Unlock the HW, prompting the boot sequence */ | 504 | if (adapter->portnum == 0) { |
345 | writel(1, | 505 | err = netxen_initialize_adapter_offload(adapter); |
346 | NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_PEGTUNE_DONE)); | 506 | if (err) |
347 | 507 | goto err_out_free_rx_buffer; | |
348 | /* Handshake with the card before we register the devices. */ | 508 | val = readl(NETXEN_CRB_NORMALIZE(adapter, |
349 | netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); | 509 | NETXEN_CAM_RAM(0x1fc))); |
350 | 510 | if (val == 0x55555555) { | |
351 | /* initialize the all the ports */ | 511 | /* This is the first boot after power up */ |
352 | adapter->active_ports = 0; | 512 | val = readl(NETXEN_CRB_NORMALIZE(adapter, |
353 | 513 | NETXEN_ROMUSB_GLB_SW_RESET)); | |
354 | for (i = 0; i < adapter->ahw.max_ports; i++) { | 514 | printk(KERN_INFO"NetXen: read 0x%08x for reset reg.\n",val); |
355 | netdev = alloc_etherdev(sizeof(struct netxen_port)); | 515 | if (val != 0x80000f) { |
356 | if (!netdev) { | 516 | /* clear the register for future unloads/loads */ |
357 | printk(KERN_ERR "%s: could not allocate netdev for port" | 517 | writel(0, NETXEN_CRB_NORMALIZE(adapter, |
358 | " %d\n", netxen_nic_driver_name, i + 1); | 518 | NETXEN_CAM_RAM(0x1fc))); |
519 | printk(KERN_ERR "ERROR in NetXen HW init sequence.\n"); | ||
520 | err = -ENODEV; | ||
359 | goto err_out_free_dev; | 521 | goto err_out_free_dev; |
360 | } | 522 | } |
361 | 523 | ||
362 | SET_MODULE_OWNER(netdev); | 524 | /* clear the register for future unloads/loads */ |
363 | SET_NETDEV_DEV(netdev, &pdev->dev); | 525 | writel(0, NETXEN_CRB_NORMALIZE(adapter, |
364 | 526 | NETXEN_CAM_RAM(0x1fc))); | |
365 | port = netdev_priv(netdev); | ||
366 | port->netdev = netdev; | ||
367 | port->pdev = pdev; | ||
368 | port->adapter = adapter; | ||
369 | port->portnum = i; /* Gigabit port number from 0-3 */ | ||
370 | |||
371 | netdev->open = netxen_nic_open; | ||
372 | netdev->stop = netxen_nic_close; | ||
373 | netdev->hard_start_xmit = netxen_nic_xmit_frame; | ||
374 | netdev->get_stats = netxen_nic_get_stats; | ||
375 | netdev->set_multicast_list = netxen_nic_set_multi; | ||
376 | netdev->set_mac_address = netxen_nic_set_mac; | ||
377 | netdev->change_mtu = netxen_nic_change_mtu; | ||
378 | netdev->tx_timeout = netxen_tx_timeout; | ||
379 | netdev->watchdog_timeo = HZ; | ||
380 | |||
381 | netxen_nic_change_mtu(netdev, netdev->mtu); | ||
382 | |||
383 | SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); | ||
384 | netdev->poll = netxen_nic_poll; | ||
385 | netdev->weight = NETXEN_NETDEV_WEIGHT; | ||
386 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
387 | netdev->poll_controller = netxen_nic_poll_controller; | ||
388 | #endif | ||
389 | /* ScatterGather support */ | ||
390 | netdev->features = NETIF_F_SG; | ||
391 | netdev->features |= NETIF_F_IP_CSUM; | ||
392 | netdev->features |= NETIF_F_TSO; | ||
393 | |||
394 | if (pci_using_dac) | ||
395 | netdev->features |= NETIF_F_HIGHDMA; | ||
396 | |||
397 | if (valid_mac) { | ||
398 | unsigned char *p = (unsigned char *)&mac_addr[i]; | ||
399 | netdev->dev_addr[0] = *(p + 5); | ||
400 | netdev->dev_addr[1] = *(p + 4); | ||
401 | netdev->dev_addr[2] = *(p + 3); | ||
402 | netdev->dev_addr[3] = *(p + 2); | ||
403 | netdev->dev_addr[4] = *(p + 1); | ||
404 | netdev->dev_addr[5] = *(p + 0); | ||
405 | |||
406 | memcpy(netdev->perm_addr, netdev->dev_addr, | ||
407 | netdev->addr_len); | ||
408 | if (!is_valid_ether_addr(netdev->perm_addr)) { | ||
409 | printk(KERN_ERR "%s: Bad MAC address " | ||
410 | "%02x:%02x:%02x:%02x:%02x:%02x.\n", | ||
411 | netxen_nic_driver_name, | ||
412 | netdev->dev_addr[0], | ||
413 | netdev->dev_addr[1], | ||
414 | netdev->dev_addr[2], | ||
415 | netdev->dev_addr[3], | ||
416 | netdev->dev_addr[4], | ||
417 | netdev->dev_addr[5]); | ||
418 | } else { | ||
419 | if (adapter->macaddr_set) | ||
420 | adapter->macaddr_set(port, | ||
421 | netdev->dev_addr); | ||
422 | } | ||
423 | } | 527 | } |
424 | INIT_WORK(&port->tx_timeout_task, netxen_tx_timeout_task); | 528 | printk(KERN_INFO "State: 0x%0x\n", |
425 | netif_carrier_off(netdev); | 529 | readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE))); |
426 | netif_stop_queue(netdev); | ||
427 | 530 | ||
428 | if ((err = register_netdev(netdev))) { | 531 | /* |
429 | printk(KERN_ERR "%s: register_netdev failed port #%d" | 532 | * Tell the hardware our version number. |
430 | " aborting\n", netxen_nic_driver_name, i + 1); | 533 | */ |
431 | err = -EIO; | 534 | i = (_NETXEN_NIC_LINUX_MAJOR << 16) |
432 | free_netdev(netdev); | 535 | | ((_NETXEN_NIC_LINUX_MINOR << 8)) |
433 | goto err_out_free_dev; | 536 | | (_NETXEN_NIC_LINUX_SUBVERSION); |
434 | } | 537 | writel(i, NETXEN_CRB_NORMALIZE(adapter, CRB_DRIVER_VERSION)); |
435 | adapter->port_count++; | 538 | |
436 | adapter->port[i] = port; | 539 | /* Unlock the HW, prompting the boot sequence */ |
540 | writel(1, | ||
541 | NETXEN_CRB_NORMALIZE(adapter, | ||
542 | NETXEN_ROMUSB_GLB_PEGTUNE_DONE)); | ||
543 | /* Handshake with the card before we register the devices. */ | ||
544 | netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); | ||
437 | } | 545 | } |
438 | writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); | 546 | |
439 | netxen_pinit_from_rom(adapter, 0); | ||
440 | udelay(500); | ||
441 | netxen_load_firmware(adapter); | ||
442 | netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); | ||
443 | /* | 547 | /* |
444 | * delay a while to ensure that the Pegs are up & running. | 548 | * See if the firmware gave us a virtual-physical port mapping. |
445 | * Otherwise, we might see some flaky behaviour. | ||
446 | */ | 549 | */ |
447 | udelay(100); | 550 | i = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_V2P(adapter->portnum))); |
551 | if (i != 0x55555555) | ||
552 | physical_port[adapter->portnum] = i; | ||
553 | |||
554 | netif_carrier_off(netdev); | ||
555 | netif_stop_queue(netdev); | ||
556 | |||
557 | if ((err = register_netdev(netdev))) { | ||
558 | printk(KERN_ERR "%s: register_netdev failed port #%d" | ||
559 | " aborting\n", netxen_nic_driver_name, | ||
560 | adapter->portnum); | ||
561 | err = -EIO; | ||
562 | goto err_out_free_dev; | ||
563 | } | ||
564 | |||
565 | pci_set_drvdata(pdev, adapter); | ||
448 | 566 | ||
449 | switch (adapter->ahw.board_type) { | 567 | switch (adapter->ahw.board_type) { |
450 | case NETXEN_NIC_GBE: | 568 | case NETXEN_NIC_GBE: |
451 | printk("%s: QUAD GbE board initialized\n", | 569 | printk(KERN_INFO "%s: QUAD GbE board initialized\n", |
452 | netxen_nic_driver_name); | 570 | netxen_nic_driver_name); |
453 | break; | 571 | break; |
454 | 572 | ||
455 | case NETXEN_NIC_XGBE: | 573 | case NETXEN_NIC_XGBE: |
456 | printk("%s: XGbE board initialized\n", netxen_nic_driver_name); | 574 | printk(KERN_INFO "%s: XGbE board initialized\n", |
457 | break; | 575 | netxen_nic_driver_name); |
576 | break; | ||
458 | } | 577 | } |
459 | 578 | ||
460 | adapter->driver_mismatch = 0; | 579 | adapter->driver_mismatch = 0; |
461 | 580 | ||
462 | return 0; | 581 | return 0; |
463 | 582 | ||
464 | err_out_free_dev: | 583 | err_out_free_dev: |
465 | if (adapter->flags & NETXEN_NIC_MSI_ENABLED) | 584 | if (adapter->portnum == 0) |
466 | pci_disable_msi(pdev); | 585 | netxen_free_adapter_offload(adapter); |
467 | for (i = 0; i < adapter->port_count; i++) { | ||
468 | port = adapter->port[i]; | ||
469 | if ((port) && (port->netdev)) { | ||
470 | unregister_netdev(port->netdev); | ||
471 | free_netdev(port->netdev); | ||
472 | } | ||
473 | } | ||
474 | 586 | ||
475 | netxen_free_adapter_offload(adapter); | 587 | err_out_free_rx_buffer: |
476 | |||
477 | err_out_free_rx_buffer: | ||
478 | for (i = 0; i < MAX_RCV_CTX; ++i) { | 588 | for (i = 0; i < MAX_RCV_CTX; ++i) { |
479 | recv_ctx = &adapter->recv_ctx[i]; | 589 | recv_ctx = &adapter->recv_ctx[i]; |
480 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { | 590 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { |
@@ -487,15 +597,16 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
487 | } | 597 | } |
488 | vfree(cmd_buf_arr); | 598 | vfree(cmd_buf_arr); |
489 | 599 | ||
490 | err_out_free_adapter: | 600 | err_out_free_adapter: |
601 | if (adapter->flags & NETXEN_NIC_MSI_ENABLED) | ||
602 | pci_disable_msi(pdev); | ||
603 | |||
491 | pci_set_drvdata(pdev, NULL); | 604 | pci_set_drvdata(pdev, NULL); |
492 | kfree(adapter); | ||
493 | 605 | ||
494 | err_out_dbunmap: | ||
495 | if (db_ptr) | 606 | if (db_ptr) |
496 | iounmap(db_ptr); | 607 | iounmap(db_ptr); |
497 | 608 | ||
498 | err_out_iounmap: | 609 | err_out_iounmap: |
499 | if (mem_ptr0) | 610 | if (mem_ptr0) |
500 | iounmap(mem_ptr0); | 611 | iounmap(mem_ptr0); |
501 | if (mem_ptr1) | 612 | if (mem_ptr1) |
@@ -503,9 +614,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
503 | if (mem_ptr2) | 614 | if (mem_ptr2) |
504 | iounmap(mem_ptr2); | 615 | iounmap(mem_ptr2); |
505 | 616 | ||
506 | err_out_free_res: | 617 | err_out_free_netdev: |
618 | free_netdev(netdev); | ||
619 | |||
620 | err_out_free_res: | ||
507 | pci_release_regions(pdev); | 621 | pci_release_regions(pdev); |
508 | err_out_disable_pdev: | 622 | |
623 | err_out_disable_pdev: | ||
509 | pci_disable_device(pdev); | 624 | pci_disable_device(pdev); |
510 | return err; | 625 | return err; |
511 | } | 626 | } |
@@ -513,7 +628,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) | |||
513 | static void __devexit netxen_nic_remove(struct pci_dev *pdev) | 628 | static void __devexit netxen_nic_remove(struct pci_dev *pdev) |
514 | { | 629 | { |
515 | struct netxen_adapter *adapter; | 630 | struct netxen_adapter *adapter; |
516 | struct netxen_port *port; | 631 | struct net_device *netdev; |
517 | struct netxen_rx_buffer *buffer; | 632 | struct netxen_rx_buffer *buffer; |
518 | struct netxen_recv_context *recv_ctx; | 633 | struct netxen_recv_context *recv_ctx; |
519 | struct netxen_rcv_desc_ctx *rcv_desc; | 634 | struct netxen_rcv_desc_ctx *rcv_desc; |
@@ -524,38 +639,34 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) | |||
524 | if (adapter == NULL) | 639 | if (adapter == NULL) |
525 | return; | 640 | return; |
526 | 641 | ||
642 | netdev = adapter->netdev; | ||
643 | |||
644 | netxen_nic_disable_int(adapter); | ||
527 | if (adapter->irq) | 645 | if (adapter->irq) |
528 | free_irq(adapter->irq, adapter); | 646 | free_irq(adapter->irq, adapter); |
529 | netxen_nic_stop_all_ports(adapter); | 647 | |
530 | /* leave the hw in the same state as reboot */ | 648 | if (adapter->stop_port) |
531 | writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); | 649 | adapter->stop_port(adapter); |
532 | netxen_pinit_from_rom(adapter, 0); | ||
533 | udelay(500); | ||
534 | netxen_load_firmware(adapter); | ||
535 | netxen_free_adapter_offload(adapter); | ||
536 | |||
537 | mdelay(1000); /* Delay for a while to drain the DMA engines */ | ||
538 | for (i = 0; i < adapter->port_count; i++) { | ||
539 | port = adapter->port[i]; | ||
540 | if ((port) && (port->netdev)) { | ||
541 | unregister_netdev(port->netdev); | ||
542 | free_netdev(port->netdev); | ||
543 | } | ||
544 | } | ||
545 | 650 | ||
546 | if ((adapter->flags & NETXEN_NIC_MSI_ENABLED)) | 651 | if ((adapter->flags & NETXEN_NIC_MSI_ENABLED)) |
547 | pci_disable_msi(pdev); | 652 | pci_disable_msi(pdev); |
548 | if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) | ||
549 | netxen_free_hw_resources(adapter); | ||
550 | 653 | ||
551 | iounmap(adapter->ahw.db_base); | 654 | if (adapter->portnum == 0) |
552 | iounmap(adapter->ahw.pci_base0); | 655 | netxen_free_adapter_offload(adapter); |
553 | iounmap(adapter->ahw.pci_base1); | ||
554 | iounmap(adapter->ahw.pci_base2); | ||
555 | 656 | ||
556 | pci_release_regions(pdev); | 657 | if (adapter->irq) |
557 | pci_disable_device(pdev); | 658 | free_irq(adapter->irq, adapter); |
558 | pci_set_drvdata(pdev, NULL); | 659 | if(adapter->portnum == 0) { |
660 | /* leave the hw in the same state as reboot */ | ||
661 | writel(0, NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE)); | ||
662 | netxen_pinit_from_rom(adapter, 0); | ||
663 | udelay(500); | ||
664 | netxen_load_firmware(adapter); | ||
665 | netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE); | ||
666 | } | ||
667 | |||
668 | if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) | ||
669 | netxen_free_hw_resources(adapter); | ||
559 | 670 | ||
560 | for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) { | 671 | for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) { |
561 | recv_ctx = &adapter->recv_ctx[ctxid]; | 672 | recv_ctx = &adapter->recv_ctx[ctxid]; |
@@ -575,8 +686,20 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) | |||
575 | } | 686 | } |
576 | } | 687 | } |
577 | 688 | ||
689 | unregister_netdev(netdev); | ||
690 | |||
578 | vfree(adapter->cmd_buf_arr); | 691 | vfree(adapter->cmd_buf_arr); |
579 | kfree(adapter); | 692 | |
693 | iounmap(adapter->ahw.db_base); | ||
694 | iounmap(adapter->ahw.pci_base0); | ||
695 | iounmap(adapter->ahw.pci_base1); | ||
696 | iounmap(adapter->ahw.pci_base2); | ||
697 | |||
698 | pci_release_regions(pdev); | ||
699 | pci_disable_device(pdev); | ||
700 | pci_set_drvdata(pdev, NULL); | ||
701 | |||
702 | free_netdev(netdev); | ||
580 | } | 703 | } |
581 | 704 | ||
582 | /* | 705 | /* |
@@ -585,8 +708,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) | |||
585 | */ | 708 | */ |
586 | static int netxen_nic_open(struct net_device *netdev) | 709 | static int netxen_nic_open(struct net_device *netdev) |
587 | { | 710 | { |
588 | struct netxen_port *port = netdev_priv(netdev); | 711 | struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv; |
589 | struct netxen_adapter *adapter = port->adapter; | ||
590 | int err = 0; | 712 | int err = 0; |
591 | int ctx, ring; | 713 | int ctx, ring; |
592 | 714 | ||
@@ -597,8 +719,6 @@ static int netxen_nic_open(struct net_device *netdev) | |||
597 | return -EIO; | 719 | return -EIO; |
598 | } | 720 | } |
599 | netxen_nic_flash_print(adapter); | 721 | netxen_nic_flash_print(adapter); |
600 | if (adapter->init_niu) | ||
601 | adapter->init_niu(adapter); | ||
602 | 722 | ||
603 | /* setup all the resources for the Phantom... */ | 723 | /* setup all the resources for the Phantom... */ |
604 | /* this include the descriptors for rcv, tx, and status */ | 724 | /* this include the descriptors for rcv, tx, and status */ |
@@ -609,21 +729,14 @@ static int netxen_nic_open(struct net_device *netdev) | |||
609 | err); | 729 | err); |
610 | return err; | 730 | return err; |
611 | } | 731 | } |
612 | if (adapter->init_port | ||
613 | && adapter->init_port(adapter, port->portnum) != 0) { | ||
614 | printk(KERN_ERR "%s: Failed to initialize port %d\n", | ||
615 | netxen_nic_driver_name, port->portnum); | ||
616 | netxen_free_hw_resources(adapter); | ||
617 | return -EIO; | ||
618 | } | ||
619 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | 732 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { |
620 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) | 733 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) |
621 | netxen_post_rx_buffers(adapter, ctx, ring); | 734 | netxen_post_rx_buffers(adapter, ctx, ring); |
622 | } | 735 | } |
623 | adapter->irq = adapter->ahw.pdev->irq; | 736 | adapter->irq = adapter->ahw.pdev->irq; |
624 | err = request_irq(adapter->ahw.pdev->irq, &netxen_intr, | 737 | err = request_irq(adapter->ahw.pdev->irq, netxen_intr, |
625 | IRQF_SHARED | IRQF_SAMPLE_RANDOM, | 738 | SA_SHIRQ | SA_SAMPLE_RANDOM, netdev->name, |
626 | netdev->name, adapter); | 739 | adapter); |
627 | if (err) { | 740 | if (err) { |
628 | printk(KERN_ERR "request_irq failed with: %d\n", err); | 741 | printk(KERN_ERR "request_irq failed with: %d\n", err); |
629 | netxen_free_hw_resources(adapter); | 742 | netxen_free_hw_resources(adapter); |
@@ -632,23 +745,28 @@ static int netxen_nic_open(struct net_device *netdev) | |||
632 | 745 | ||
633 | adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; | 746 | adapter->is_up = NETXEN_ADAPTER_UP_MAGIC; |
634 | } | 747 | } |
635 | adapter->active_ports++; | 748 | if (!adapter->driver_mismatch) |
636 | if (adapter->active_ports == 1) { | 749 | mod_timer(&adapter->watchdog_timer, jiffies); |
637 | if (!adapter->driver_mismatch) | ||
638 | mod_timer(&adapter->watchdog_timer, jiffies); | ||
639 | 750 | ||
640 | netxen_nic_enable_int(adapter); | 751 | netxen_nic_enable_int(adapter); |
641 | } | ||
642 | 752 | ||
643 | /* Done here again so that even if phantom sw overwrote it, | 753 | /* Done here again so that even if phantom sw overwrote it, |
644 | * we set it */ | 754 | * we set it */ |
645 | if (adapter->macaddr_set) | 755 | if (adapter->macaddr_set) |
646 | adapter->macaddr_set(port, netdev->dev_addr); | 756 | adapter->macaddr_set(adapter, netdev->dev_addr); |
647 | netxen_nic_set_link_parameters(port); | 757 | if (adapter->init_port |
758 | && adapter->init_port(adapter, adapter->portnum) != 0) { | ||
759 | del_timer_sync(&adapter->watchdog_timer); | ||
760 | printk(KERN_ERR "%s: Failed to initialize port %d\n", | ||
761 | netxen_nic_driver_name, adapter->portnum); | ||
762 | return -EIO; | ||
763 | } | ||
764 | |||
765 | netxen_nic_set_link_parameters(adapter); | ||
648 | 766 | ||
649 | netxen_nic_set_multi(netdev); | 767 | netxen_nic_set_multi(netdev); |
650 | if (adapter->set_mtu) | 768 | if (adapter->set_mtu) |
651 | adapter->set_mtu(port, netdev->mtu); | 769 | adapter->set_mtu(adapter, netdev->mtu); |
652 | 770 | ||
653 | if (!adapter->driver_mismatch) | 771 | if (!adapter->driver_mismatch) |
654 | netif_start_queue(netdev); | 772 | netif_start_queue(netdev); |
@@ -661,8 +779,7 @@ static int netxen_nic_open(struct net_device *netdev) | |||
661 | */ | 779 | */ |
662 | static int netxen_nic_close(struct net_device *netdev) | 780 | static int netxen_nic_close(struct net_device *netdev) |
663 | { | 781 | { |
664 | struct netxen_port *port = netdev_priv(netdev); | 782 | struct netxen_adapter *adapter = netdev_priv(netdev); |
665 | struct netxen_adapter *adapter = port->adapter; | ||
666 | int i, j; | 783 | int i, j; |
667 | struct netxen_cmd_buffer *cmd_buff; | 784 | struct netxen_cmd_buffer *cmd_buff; |
668 | struct netxen_skb_frag *buffrag; | 785 | struct netxen_skb_frag *buffrag; |
@@ -670,47 +787,39 @@ static int netxen_nic_close(struct net_device *netdev) | |||
670 | netif_carrier_off(netdev); | 787 | netif_carrier_off(netdev); |
671 | netif_stop_queue(netdev); | 788 | netif_stop_queue(netdev); |
672 | 789 | ||
673 | adapter->active_ports--; | 790 | cmd_buff = adapter->cmd_buf_arr; |
674 | 791 | for (i = 0; i < adapter->max_tx_desc_count; i++) { | |
675 | if (!adapter->active_ports) { | 792 | buffrag = cmd_buff->frag_array; |
676 | netxen_nic_disable_int(adapter); | 793 | if (buffrag->dma) { |
677 | cmd_buff = adapter->cmd_buf_arr; | 794 | pci_unmap_single(adapter->pdev, buffrag->dma, |
678 | for (i = 0; i < adapter->max_tx_desc_count; i++) { | 795 | buffrag->length, PCI_DMA_TODEVICE); |
679 | buffrag = cmd_buff->frag_array; | 796 | buffrag->dma = (u64) NULL; |
797 | } | ||
798 | for (j = 0; j < cmd_buff->frag_count; j++) { | ||
799 | buffrag++; | ||
680 | if (buffrag->dma) { | 800 | if (buffrag->dma) { |
681 | pci_unmap_single(port->pdev, buffrag->dma, | 801 | pci_unmap_page(adapter->pdev, buffrag->dma, |
682 | buffrag->length, | 802 | buffrag->length, |
683 | PCI_DMA_TODEVICE); | 803 | PCI_DMA_TODEVICE); |
684 | buffrag->dma = (u64) NULL; | 804 | buffrag->dma = (u64) NULL; |
685 | } | 805 | } |
686 | for (j = 0; j < cmd_buff->frag_count; j++) { | ||
687 | buffrag++; | ||
688 | if (buffrag->dma) { | ||
689 | pci_unmap_page(port->pdev, | ||
690 | buffrag->dma, | ||
691 | buffrag->length, | ||
692 | PCI_DMA_TODEVICE); | ||
693 | buffrag->dma = (u64) NULL; | ||
694 | } | ||
695 | } | ||
696 | /* Free the skb we received in netxen_nic_xmit_frame */ | ||
697 | if (cmd_buff->skb) { | ||
698 | dev_kfree_skb_any(cmd_buff->skb); | ||
699 | cmd_buff->skb = NULL; | ||
700 | } | ||
701 | cmd_buff++; | ||
702 | } | 806 | } |
703 | FLUSH_SCHEDULED_WORK(); | 807 | /* Free the skb we received in netxen_nic_xmit_frame */ |
704 | del_timer_sync(&adapter->watchdog_timer); | 808 | if (cmd_buff->skb) { |
809 | dev_kfree_skb_any(cmd_buff->skb); | ||
810 | cmd_buff->skb = NULL; | ||
811 | } | ||
812 | cmd_buff++; | ||
705 | } | 813 | } |
814 | FLUSH_SCHEDULED_WORK(); | ||
815 | del_timer_sync(&adapter->watchdog_timer); | ||
706 | 816 | ||
707 | return 0; | 817 | return 0; |
708 | } | 818 | } |
709 | 819 | ||
710 | static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | 820 | static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) |
711 | { | 821 | { |
712 | struct netxen_port *port = netdev_priv(netdev); | 822 | struct netxen_adapter *adapter = netdev_priv(netdev); |
713 | struct netxen_adapter *adapter = port->adapter; | ||
714 | struct netxen_hardware_context *hw = &adapter->ahw; | 823 | struct netxen_hardware_context *hw = &adapter->ahw; |
715 | unsigned int first_seg_len = skb->len - skb->data_len; | 824 | unsigned int first_seg_len = skb->len - skb->data_len; |
716 | struct netxen_skb_frag *buffrag; | 825 | struct netxen_skb_frag *buffrag; |
@@ -728,12 +837,12 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
728 | u32 last_cmd_consumer = 0; | 837 | u32 last_cmd_consumer = 0; |
729 | int no_of_desc; | 838 | int no_of_desc; |
730 | 839 | ||
731 | port->stats.xmitcalled++; | 840 | adapter->stats.xmitcalled++; |
732 | frag_count = skb_shinfo(skb)->nr_frags + 1; | 841 | frag_count = skb_shinfo(skb)->nr_frags + 1; |
733 | 842 | ||
734 | if (unlikely(skb->len <= 0)) { | 843 | if (unlikely(skb->len <= 0)) { |
735 | dev_kfree_skb_any(skb); | 844 | dev_kfree_skb_any(skb); |
736 | port->stats.badskblen++; | 845 | adapter->stats.badskblen++; |
737 | return NETDEV_TX_OK; | 846 | return NETDEV_TX_OK; |
738 | } | 847 | } |
739 | 848 | ||
@@ -742,7 +851,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
742 | "too large, can handle only %d frags\n", | 851 | "too large, can handle only %d frags\n", |
743 | netxen_nic_driver_name, netdev->name, | 852 | netxen_nic_driver_name, netdev->name, |
744 | frag_count, MAX_BUFFERS_PER_CMD); | 853 | frag_count, MAX_BUFFERS_PER_CMD); |
745 | port->stats.txdropped++; | 854 | adapter->stats.txdropped++; |
746 | if ((++dropped_packet & 0xff) == 0xff) | 855 | if ((++dropped_packet & 0xff) == 0xff) |
747 | printk("%s: %s droppped packets = %d\n", | 856 | printk("%s: %s droppped packets = %d\n", |
748 | netxen_nic_driver_name, netdev->name, | 857 | netxen_nic_driver_name, netdev->name, |
@@ -759,7 +868,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
759 | */ | 868 | */ |
760 | retry_getting_window: | 869 | retry_getting_window: |
761 | spin_lock_bh(&adapter->tx_lock); | 870 | spin_lock_bh(&adapter->tx_lock); |
762 | if (adapter->total_threads == MAX_XMIT_PRODUCERS) { | 871 | if (adapter->total_threads >= MAX_XMIT_PRODUCERS) { |
763 | spin_unlock_bh(&adapter->tx_lock); | 872 | spin_unlock_bh(&adapter->tx_lock); |
764 | /* | 873 | /* |
765 | * Yield CPU | 874 | * Yield CPU |
@@ -792,15 +901,8 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
792 | if ((k + no_of_desc) >= | 901 | if ((k + no_of_desc) >= |
793 | ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count : | 902 | ((last_cmd_consumer <= k) ? last_cmd_consumer + max_tx_desc_count : |
794 | last_cmd_consumer)) { | 903 | last_cmd_consumer)) { |
795 | port->stats.nocmddescriptor++; | ||
796 | DPRINTK(ERR, "No command descriptors available," | ||
797 | " producer = %d, consumer = %d count=%llu," | ||
798 | " dropping packet\n", producer, | ||
799 | adapter->last_cmd_consumer, | ||
800 | port->stats.nocmddescriptor); | ||
801 | |||
802 | netif_stop_queue(netdev); | 904 | netif_stop_queue(netdev); |
803 | port->flags |= NETXEN_NETDEV_STATUS; | 905 | adapter->flags |= NETXEN_NETDEV_STATUS; |
804 | spin_unlock_bh(&adapter->tx_lock); | 906 | spin_unlock_bh(&adapter->tx_lock); |
805 | return NETDEV_TX_BUSY; | 907 | return NETDEV_TX_BUSY; |
806 | } | 908 | } |
@@ -828,16 +930,17 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
828 | pbuf->skb = skb; | 930 | pbuf->skb = skb; |
829 | pbuf->cmd = TX_ETHER_PKT; | 931 | pbuf->cmd = TX_ETHER_PKT; |
830 | pbuf->frag_count = frag_count; | 932 | pbuf->frag_count = frag_count; |
831 | pbuf->port = port->portnum; | 933 | pbuf->port = adapter->portnum; |
832 | buffrag = &pbuf->frag_array[0]; | 934 | buffrag = &pbuf->frag_array[0]; |
833 | buffrag->dma = pci_map_single(port->pdev, skb->data, first_seg_len, | 935 | buffrag->dma = pci_map_single(adapter->pdev, skb->data, first_seg_len, |
834 | PCI_DMA_TODEVICE); | 936 | PCI_DMA_TODEVICE); |
835 | buffrag->length = first_seg_len; | 937 | buffrag->length = first_seg_len; |
836 | netxen_set_cmd_desc_totallength(hwdesc, skb->len); | 938 | netxen_set_cmd_desc_totallength(hwdesc, skb->len); |
837 | netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count); | 939 | netxen_set_cmd_desc_num_of_buff(hwdesc, frag_count); |
838 | netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT); | 940 | netxen_set_cmd_desc_opcode(hwdesc, TX_ETHER_PKT); |
839 | 941 | ||
840 | netxen_set_cmd_desc_port(hwdesc, port->portnum); | 942 | netxen_set_cmd_desc_port(hwdesc, adapter->portnum); |
943 | netxen_set_cmd_desc_ctxid(hwdesc, adapter->portnum); | ||
841 | hwdesc->buffer1_length = cpu_to_le16(first_seg_len); | 944 | hwdesc->buffer1_length = cpu_to_le16(first_seg_len); |
842 | hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); | 945 | hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); |
843 | 946 | ||
@@ -860,7 +963,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
860 | offset = frag->page_offset; | 963 | offset = frag->page_offset; |
861 | 964 | ||
862 | temp_len = len; | 965 | temp_len = len; |
863 | temp_dma = pci_map_page(port->pdev, frag->page, offset, | 966 | temp_dma = pci_map_page(adapter->pdev, frag->page, offset, |
864 | len, PCI_DMA_TODEVICE); | 967 | len, PCI_DMA_TODEVICE); |
865 | 968 | ||
866 | buffrag++; | 969 | buffrag++; |
@@ -927,21 +1030,29 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
927 | producer = get_next_index(producer, max_tx_desc_count); | 1030 | producer = get_next_index(producer, max_tx_desc_count); |
928 | } | 1031 | } |
929 | } | 1032 | } |
1033 | |||
1034 | i = netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]); | ||
1035 | |||
1036 | hw->cmd_desc_head[saved_producer].flags_opcode = | ||
1037 | cpu_to_le16(hw->cmd_desc_head[saved_producer].flags_opcode); | ||
1038 | hw->cmd_desc_head[saved_producer].num_of_buffers_total_length = | ||
1039 | cpu_to_le32(hw->cmd_desc_head[saved_producer]. | ||
1040 | num_of_buffers_total_length); | ||
1041 | |||
930 | spin_lock_bh(&adapter->tx_lock); | 1042 | spin_lock_bh(&adapter->tx_lock); |
931 | port->stats.txbytes += | 1043 | adapter->stats.txbytes += i; |
932 | netxen_get_cmd_desc_totallength(&hw->cmd_desc_head[saved_producer]); | 1044 | |
933 | /* Code to update the adapter considering how many producer threads | 1045 | /* Code to update the adapter considering how many producer threads |
934 | are currently working */ | 1046 | are currently working */ |
935 | if ((--adapter->num_threads) == 0) { | 1047 | if ((--adapter->num_threads) == 0) { |
936 | /* This is the last thread */ | 1048 | /* This is the last thread */ |
937 | u32 crb_producer = adapter->cmd_producer; | 1049 | u32 crb_producer = adapter->cmd_producer; |
938 | writel(crb_producer, | 1050 | netxen_nic_update_cmd_producer(adapter, crb_producer); |
939 | NETXEN_CRB_NORMALIZE(adapter, CRB_CMD_PRODUCER_OFFSET)); | ||
940 | wmb(); | 1051 | wmb(); |
941 | adapter->total_threads = 0; | 1052 | adapter->total_threads = 0; |
942 | } | 1053 | } |
943 | 1054 | ||
944 | port->stats.xmitfinished++; | 1055 | adapter->stats.xmitfinished++; |
945 | spin_unlock_bh(&adapter->tx_lock); | 1056 | spin_unlock_bh(&adapter->tx_lock); |
946 | 1057 | ||
947 | netdev->trans_start = jiffies; | 1058 | netdev->trans_start = jiffies; |
@@ -961,27 +1072,26 @@ static void netxen_watchdog(unsigned long v) | |||
961 | 1072 | ||
962 | static void netxen_tx_timeout(struct net_device *netdev) | 1073 | static void netxen_tx_timeout(struct net_device *netdev) |
963 | { | 1074 | { |
964 | struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev); | 1075 | struct netxen_adapter *adapter = (struct netxen_adapter *) |
965 | 1076 | netdev_priv(netdev); | |
966 | SCHEDULE_WORK(&port->tx_timeout_task); | 1077 | SCHEDULE_WORK(&adapter->tx_timeout_task); |
967 | } | 1078 | } |
968 | 1079 | ||
969 | static void netxen_tx_timeout_task(struct work_struct *work) | 1080 | static void netxen_tx_timeout_task(struct work_struct *work) |
970 | { | 1081 | { |
971 | struct netxen_port *port = | 1082 | struct netxen_adapter *adapter = |
972 | container_of(work, struct netxen_port, tx_timeout_task); | 1083 | container_of(work, struct netxen_adapter, tx_timeout_task); |
973 | struct net_device *netdev = port->netdev; | ||
974 | unsigned long flags; | 1084 | unsigned long flags; |
975 | 1085 | ||
976 | printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", | 1086 | printk(KERN_ERR "%s %s: transmit timeout, resetting.\n", |
977 | netxen_nic_driver_name, netdev->name); | 1087 | netxen_nic_driver_name, adapter->netdev->name); |
978 | 1088 | ||
979 | spin_lock_irqsave(&port->adapter->lock, flags); | 1089 | spin_lock_irqsave(&adapter->lock, flags); |
980 | netxen_nic_close(netdev); | 1090 | netxen_nic_close(adapter->netdev); |
981 | netxen_nic_open(netdev); | 1091 | netxen_nic_open(adapter->netdev); |
982 | spin_unlock_irqrestore(&port->adapter->lock, flags); | 1092 | spin_unlock_irqrestore(&adapter->lock, flags); |
983 | netdev->trans_start = jiffies; | 1093 | adapter->netdev->trans_start = jiffies; |
984 | netif_wake_queue(netdev); | 1094 | netif_wake_queue(adapter->netdev); |
985 | } | 1095 | } |
986 | 1096 | ||
987 | static int | 1097 | static int |
@@ -990,17 +1100,16 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) | |||
990 | u32 ret = 0; | 1100 | u32 ret = 0; |
991 | 1101 | ||
992 | DPRINTK(INFO, "Entered handle ISR\n"); | 1102 | DPRINTK(INFO, "Entered handle ISR\n"); |
993 | |||
994 | adapter->stats.ints++; | 1103 | adapter->stats.ints++; |
995 | 1104 | ||
996 | if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { | 1105 | if (!(adapter->flags & NETXEN_NIC_MSI_ENABLED)) { |
997 | int count = 0; | 1106 | int count = 0; |
998 | u32 mask; | 1107 | u32 mask; |
999 | mask = readl(pci_base_offset(adapter, ISR_INT_VECTOR)); | 1108 | u32 our_int = 0; |
1000 | if ((mask & 0x80) == 0) { | 1109 | our_int = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_INT_VECTOR)); |
1001 | /* not our interrupt */ | 1110 | /* not our interrupt */ |
1111 | if ((our_int & (0x80 << adapter->portnum)) == 0) | ||
1002 | return ret; | 1112 | return ret; |
1003 | } | ||
1004 | netxen_nic_disable_int(adapter); | 1113 | netxen_nic_disable_int(adapter); |
1005 | /* Window = 0 or 1 */ | 1114 | /* Window = 0 or 1 */ |
1006 | do { | 1115 | do { |
@@ -1012,7 +1121,6 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) | |||
1012 | printk("Could not disable interrupt completely\n"); | 1121 | printk("Could not disable interrupt completely\n"); |
1013 | 1122 | ||
1014 | } | 1123 | } |
1015 | adapter->stats.hostints++; | ||
1016 | 1124 | ||
1017 | if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) { | 1125 | if (netxen_nic_rx_has_work(adapter) || netxen_nic_tx_has_work(adapter)) { |
1018 | if (netif_rx_schedule_prep(netdev)) { | 1126 | if (netif_rx_schedule_prep(netdev)) { |
@@ -1046,33 +1154,24 @@ netxen_handle_int(struct netxen_adapter *adapter, struct net_device *netdev) | |||
1046 | irqreturn_t netxen_intr(int irq, void *data) | 1154 | irqreturn_t netxen_intr(int irq, void *data) |
1047 | { | 1155 | { |
1048 | struct netxen_adapter *adapter; | 1156 | struct netxen_adapter *adapter; |
1049 | struct netxen_port *port; | ||
1050 | struct net_device *netdev; | 1157 | struct net_device *netdev; |
1051 | int i; | ||
1052 | 1158 | ||
1053 | if (unlikely(!irq)) { | 1159 | if (unlikely(!irq)) { |
1054 | return IRQ_NONE; /* Not our interrupt */ | 1160 | return IRQ_NONE; /* Not our interrupt */ |
1055 | } | 1161 | } |
1056 | 1162 | ||
1057 | adapter = (struct netxen_adapter *)data; | 1163 | adapter = (struct netxen_adapter *)data; |
1058 | for (i = 0; i < adapter->ahw.max_ports; i++) { | 1164 | netdev = adapter->netdev; |
1059 | port = adapter->port[i]; | 1165 | /* process our status queue (for all 4 ports) */ |
1060 | netdev = port->netdev; | 1166 | if (netif_running(netdev)) |
1061 | 1167 | netxen_handle_int(adapter, netdev); | |
1062 | /* process our status queue (for all 4 ports) */ | ||
1063 | if (netif_running(netdev)) { | ||
1064 | netxen_handle_int(adapter, netdev); | ||
1065 | break; | ||
1066 | } | ||
1067 | } | ||
1068 | 1168 | ||
1069 | return IRQ_HANDLED; | 1169 | return IRQ_HANDLED; |
1070 | } | 1170 | } |
1071 | 1171 | ||
1072 | static int netxen_nic_poll(struct net_device *netdev, int *budget) | 1172 | static int netxen_nic_poll(struct net_device *netdev, int *budget) |
1073 | { | 1173 | { |
1074 | struct netxen_port *port = (struct netxen_port *)netdev_priv(netdev); | 1174 | struct netxen_adapter *adapter = netdev_priv(netdev); |
1075 | struct netxen_adapter *adapter = port->adapter; | ||
1076 | int work_to_do = min(*budget, netdev->quota); | 1175 | int work_to_do = min(*budget, netdev->quota); |
1077 | int done = 1; | 1176 | int done = 1; |
1078 | int ctx; | 1177 | int ctx; |
@@ -1080,7 +1179,6 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) | |||
1080 | int work_done = 0; | 1179 | int work_done = 0; |
1081 | 1180 | ||
1082 | DPRINTK(INFO, "polling for %d descriptors\n", *budget); | 1181 | DPRINTK(INFO, "polling for %d descriptors\n", *budget); |
1083 | port->stats.polled++; | ||
1084 | 1182 | ||
1085 | work_done = 0; | 1183 | work_done = 0; |
1086 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | 1184 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { |
@@ -1124,8 +1222,7 @@ static int netxen_nic_poll(struct net_device *netdev, int *budget) | |||
1124 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1222 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1125 | static void netxen_nic_poll_controller(struct net_device *netdev) | 1223 | static void netxen_nic_poll_controller(struct net_device *netdev) |
1126 | { | 1224 | { |
1127 | struct netxen_port *port = netdev_priv(netdev); | 1225 | struct netxen_adapter *adapter = netdev_priv(netdev); |
1128 | struct netxen_adapter *adapter = port->adapter; | ||
1129 | disable_irq(adapter->irq); | 1226 | disable_irq(adapter->irq); |
1130 | netxen_intr(adapter->irq, adapter); | 1227 | netxen_intr(adapter->irq, adapter); |
1131 | enable_irq(adapter->irq); | 1228 | enable_irq(adapter->irq); |
diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index d5d95074e569..cef90a78351e 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c | |||
@@ -88,12 +88,13 @@ static inline int phy_unlock(struct netxen_adapter *adapter) | |||
88 | * -1 on error | 88 | * -1 on error |
89 | * | 89 | * |
90 | */ | 90 | */ |
91 | int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, | 91 | int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long reg, |
92 | long reg, __u32 * readval) | 92 | __u32 * readval) |
93 | { | 93 | { |
94 | long timeout = 0; | 94 | long timeout = 0; |
95 | long result = 0; | 95 | long result = 0; |
96 | long restore = 0; | 96 | long restore = 0; |
97 | long phy = physical_port[adapter->portnum]; | ||
97 | __u32 address; | 98 | __u32 address; |
98 | __u32 command; | 99 | __u32 command; |
99 | __u32 status; | 100 | __u32 status; |
@@ -183,12 +184,13 @@ int netxen_niu_gbe_phy_read(struct netxen_adapter *adapter, long phy, | |||
183 | * -1 on error | 184 | * -1 on error |
184 | * | 185 | * |
185 | */ | 186 | */ |
186 | int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, | 187 | int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, long reg, |
187 | long phy, long reg, __u32 val) | 188 | __u32 val) |
188 | { | 189 | { |
189 | long timeout = 0; | 190 | long timeout = 0; |
190 | long result = 0; | 191 | long result = 0; |
191 | long restore = 0; | 192 | long restore = 0; |
193 | long phy = physical_port[adapter->portnum]; | ||
192 | __u32 address; | 194 | __u32 address; |
193 | __u32 command; | 195 | __u32 command; |
194 | __u32 status; | 196 | __u32 status; |
@@ -258,15 +260,13 @@ int netxen_niu_gbe_phy_write(struct netxen_adapter *adapter, | |||
258 | return result; | 260 | return result; |
259 | } | 261 | } |
260 | 262 | ||
261 | int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter, | 263 | int netxen_niu_xgbe_enable_phy_interrupts(struct netxen_adapter *adapter) |
262 | int port) | ||
263 | { | 264 | { |
264 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f); | 265 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x3f); |
265 | return 0; | 266 | return 0; |
266 | } | 267 | } |
267 | 268 | ||
268 | int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, | 269 | int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter) |
269 | int port) | ||
270 | { | 270 | { |
271 | int result = 0; | 271 | int result = 0; |
272 | __u32 enable = 0; | 272 | __u32 enable = 0; |
@@ -275,7 +275,7 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, | |||
275 | netxen_set_phy_int_speed_changed(enable); | 275 | netxen_set_phy_int_speed_changed(enable); |
276 | 276 | ||
277 | if (0 != | 277 | if (0 != |
278 | netxen_niu_gbe_phy_write(adapter, port, | 278 | netxen_niu_gbe_phy_write(adapter, |
279 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, | 279 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, |
280 | enable)) | 280 | enable)) |
281 | result = -EIO; | 281 | result = -EIO; |
@@ -283,38 +283,34 @@ int netxen_niu_gbe_enable_phy_interrupts(struct netxen_adapter *adapter, | |||
283 | return result; | 283 | return result; |
284 | } | 284 | } |
285 | 285 | ||
286 | int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter, | 286 | int netxen_niu_xgbe_disable_phy_interrupts(struct netxen_adapter *adapter) |
287 | int port) | ||
288 | { | 287 | { |
289 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f); | 288 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_INT_MASK, 0x7f); |
290 | return 0; | 289 | return 0; |
291 | } | 290 | } |
292 | 291 | ||
293 | int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter, | 292 | int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter) |
294 | int port) | ||
295 | { | 293 | { |
296 | int result = 0; | 294 | int result = 0; |
297 | if (0 != | 295 | if (0 != |
298 | netxen_niu_gbe_phy_write(adapter, port, | 296 | netxen_niu_gbe_phy_write(adapter, |
299 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0)) | 297 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_ENABLE, 0)) |
300 | result = -EIO; | 298 | result = -EIO; |
301 | 299 | ||
302 | return result; | 300 | return result; |
303 | } | 301 | } |
304 | 302 | ||
305 | int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter, | 303 | int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter) |
306 | int port) | ||
307 | { | 304 | { |
308 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1); | 305 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1); |
309 | return 0; | 306 | return 0; |
310 | } | 307 | } |
311 | 308 | ||
312 | int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter, | 309 | int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter) |
313 | int port) | ||
314 | { | 310 | { |
315 | int result = 0; | 311 | int result = 0; |
316 | if (0 != | 312 | if (0 != |
317 | netxen_niu_gbe_phy_write(adapter, port, | 313 | netxen_niu_gbe_phy_write(adapter, |
318 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, | 314 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, |
319 | -EIO)) | 315 | -EIO)) |
320 | result = -EIO; | 316 | result = -EIO; |
@@ -355,9 +351,9 @@ void netxen_niu_gbe_set_mii_mode(struct netxen_adapter *adapter, | |||
355 | 0x5); | 351 | 0x5); |
356 | } | 352 | } |
357 | 353 | ||
358 | if (netxen_niu_gbe_enable_phy_interrupts(adapter, port)) | 354 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
359 | printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); | 355 | printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); |
360 | if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) | 356 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
361 | printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); | 357 | printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); |
362 | } | 358 | } |
363 | 359 | ||
@@ -393,9 +389,9 @@ void netxen_niu_gbe_set_gmii_mode(struct netxen_adapter *adapter, | |||
393 | 0x5); | 389 | 0x5); |
394 | } | 390 | } |
395 | 391 | ||
396 | if (netxen_niu_gbe_enable_phy_interrupts(adapter, port)) | 392 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
397 | printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); | 393 | printk(KERN_ERR PFX "ERROR enabling PHY interrupts\n"); |
398 | if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) | 394 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
399 | printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); | 395 | printk(KERN_ERR PFX "ERROR clearing PHY interrupts\n"); |
400 | } | 396 | } |
401 | 397 | ||
@@ -404,11 +400,11 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) | |||
404 | int result = 0; | 400 | int result = 0; |
405 | __u32 status; | 401 | __u32 status; |
406 | if (adapter->disable_phy_interrupts) | 402 | if (adapter->disable_phy_interrupts) |
407 | adapter->disable_phy_interrupts(adapter, port); | 403 | adapter->disable_phy_interrupts(adapter); |
408 | mdelay(2); | 404 | mdelay(2); |
409 | 405 | ||
410 | if (0 == | 406 | if (0 == |
411 | netxen_niu_gbe_phy_read(adapter, port, | 407 | netxen_niu_gbe_phy_read(adapter, |
412 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, | 408 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
413 | &status)) { | 409 | &status)) { |
414 | if (netxen_get_phy_link(status)) { | 410 | if (netxen_get_phy_link(status)) { |
@@ -439,13 +435,13 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) | |||
439 | | NETXEN_GB_MAC_ENABLE_TX_RX | 435 | | NETXEN_GB_MAC_ENABLE_TX_RX |
440 | | | 436 | | |
441 | NETXEN_GB_MAC_PAUSED_FRMS); | 437 | NETXEN_GB_MAC_PAUSED_FRMS); |
442 | if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) | 438 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
443 | printk(KERN_ERR PFX | 439 | printk(KERN_ERR PFX |
444 | "ERROR clearing PHY interrupts\n"); | 440 | "ERROR clearing PHY interrupts\n"); |
445 | if (netxen_niu_gbe_enable_phy_interrupts(adapter, port)) | 441 | if (netxen_niu_gbe_enable_phy_interrupts(adapter)) |
446 | printk(KERN_ERR PFX | 442 | printk(KERN_ERR PFX |
447 | "ERROR enabling PHY interrupts\n"); | 443 | "ERROR enabling PHY interrupts\n"); |
448 | if (netxen_niu_gbe_clear_phy_interrupts(adapter, port)) | 444 | if (netxen_niu_gbe_clear_phy_interrupts(adapter)) |
449 | printk(KERN_ERR PFX | 445 | printk(KERN_ERR PFX |
450 | "ERROR clearing PHY interrupts\n"); | 446 | "ERROR clearing PHY interrupts\n"); |
451 | result = -1; | 447 | result = -1; |
@@ -458,26 +454,18 @@ int netxen_niu_gbe_init_port(struct netxen_adapter *adapter, int port) | |||
458 | 454 | ||
459 | int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) | 455 | int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port) |
460 | { | 456 | { |
461 | u32 reg = 0, ret = 0; | 457 | u32 reg; |
458 | u32 portnum = physical_port[adapter->portnum]; | ||
462 | 459 | ||
463 | if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { | 460 | netxen_crb_writelit_adapter(adapter, |
464 | netxen_crb_writelit_adapter(adapter, | 461 | NETXEN_NIU_XGE_CONFIG_0+(0x10000*portnum), 0x5); |
465 | NETXEN_NIU_XG1_CONFIG_0, 0x5); | 462 | netxen_nic_hw_read_wx(adapter, |
466 | /* XXX hack for Mez cards: both ports in promisc mode */ | 463 | NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), ®, 4); |
467 | netxen_nic_hw_read_wx(adapter, | 464 | reg = (reg & ~0x2000UL); |
468 | NETXEN_NIU_XGE_CONFIG_1, ®, 4); | 465 | netxen_crb_writelit_adapter(adapter, |
469 | reg = (reg | 0x2000UL); | 466 | NETXEN_NIU_XGE_CONFIG_1+(0x10000*portnum), reg); |
470 | netxen_crb_writelit_adapter(adapter, | ||
471 | NETXEN_NIU_XGE_CONFIG_1, reg); | ||
472 | reg = 0; | ||
473 | netxen_nic_hw_read_wx(adapter, | ||
474 | NETXEN_NIU_XG1_CONFIG_1, ®, 4); | ||
475 | reg = (reg | 0x2000UL); | ||
476 | netxen_crb_writelit_adapter(adapter, | ||
477 | NETXEN_NIU_XG1_CONFIG_1, reg); | ||
478 | } | ||
479 | 467 | ||
480 | return ret; | 468 | return 0; |
481 | } | 469 | } |
482 | 470 | ||
483 | /* | 471 | /* |
@@ -498,7 +486,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, | |||
498 | * The read of the PHY INT status will clear the pending | 486 | * The read of the PHY INT status will clear the pending |
499 | * interrupt status | 487 | * interrupt status |
500 | */ | 488 | */ |
501 | if (netxen_niu_gbe_phy_read(adapter, port, | 489 | if (netxen_niu_gbe_phy_read(adapter, |
502 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, | 490 | NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS, |
503 | &int_src) != 0) | 491 | &int_src) != 0) |
504 | result = -EINVAL; | 492 | result = -EINVAL; |
@@ -535,7 +523,7 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, | |||
535 | printk(KERN_INFO PFX | 523 | printk(KERN_INFO PFX |
536 | "speed_changed or link status changed"); | 524 | "speed_changed or link status changed"); |
537 | if (netxen_niu_gbe_phy_read | 525 | if (netxen_niu_gbe_phy_read |
538 | (adapter, port, | 526 | (adapter, |
539 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, | 527 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, |
540 | &status) == 0) { | 528 | &status) == 0) { |
541 | if (netxen_get_phy_speed(status) == 2) { | 529 | if (netxen_get_phy_speed(status) == 2) { |
@@ -581,10 +569,11 @@ int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter, | |||
581 | * Note that the passed-in value must already be in network byte order. | 569 | * Note that the passed-in value must already be in network byte order. |
582 | */ | 570 | */ |
583 | int netxen_niu_macaddr_get(struct netxen_adapter *adapter, | 571 | int netxen_niu_macaddr_get(struct netxen_adapter *adapter, |
584 | int phy, netxen_ethernet_macaddr_t * addr) | 572 | netxen_ethernet_macaddr_t * addr) |
585 | { | 573 | { |
586 | u32 stationhigh; | 574 | u32 stationhigh; |
587 | u32 stationlow; | 575 | u32 stationlow; |
576 | int phy = physical_port[adapter->portnum]; | ||
588 | u8 val[8]; | 577 | u8 val[8]; |
589 | 578 | ||
590 | if (addr == NULL) | 579 | if (addr == NULL) |
@@ -610,13 +599,12 @@ int netxen_niu_macaddr_get(struct netxen_adapter *adapter, | |||
610 | * Set the station MAC address. | 599 | * Set the station MAC address. |
611 | * Note that the passed-in value must already be in network byte order. | 600 | * Note that the passed-in value must already be in network byte order. |
612 | */ | 601 | */ |
613 | int netxen_niu_macaddr_set(struct netxen_port *port, | 602 | int netxen_niu_macaddr_set(struct netxen_adapter *adapter, |
614 | netxen_ethernet_macaddr_t addr) | 603 | netxen_ethernet_macaddr_t addr) |
615 | { | 604 | { |
616 | u8 temp[4]; | 605 | u8 temp[4]; |
617 | u32 val; | 606 | u32 val; |
618 | struct netxen_adapter *adapter = port->adapter; | 607 | int phy = physical_port[adapter->portnum]; |
619 | int phy = port->portnum; | ||
620 | unsigned char mac_addr[6]; | 608 | unsigned char mac_addr[6]; |
621 | int i; | 609 | int i; |
622 | 610 | ||
@@ -634,7 +622,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port, | |||
634 | (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) | 622 | (adapter, NETXEN_NIU_GB_STATION_ADDR_0(phy), &val, 4)) |
635 | return -2; | 623 | return -2; |
636 | 624 | ||
637 | netxen_niu_macaddr_get(adapter, phy, | 625 | netxen_niu_macaddr_get(adapter, |
638 | (netxen_ethernet_macaddr_t *) mac_addr); | 626 | (netxen_ethernet_macaddr_t *) mac_addr); |
639 | if (memcmp(mac_addr, addr, 6) == 0) | 627 | if (memcmp(mac_addr, addr, 6) == 0) |
640 | break; | 628 | break; |
@@ -642,7 +630,7 @@ int netxen_niu_macaddr_set(struct netxen_port *port, | |||
642 | 630 | ||
643 | if (i == 10) { | 631 | if (i == 10) { |
644 | printk(KERN_ERR "%s: cannot set Mac addr for %s\n", | 632 | printk(KERN_ERR "%s: cannot set Mac addr for %s\n", |
645 | netxen_nic_driver_name, port->netdev->name); | 633 | netxen_nic_driver_name, adapter->netdev->name); |
646 | printk(KERN_ERR "MAC address set: " | 634 | printk(KERN_ERR "MAC address set: " |
647 | "%02x:%02x:%02x:%02x:%02x:%02x.\n", | 635 | "%02x:%02x:%02x:%02x:%02x:%02x.\n", |
648 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); | 636 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); |
@@ -735,13 +723,13 @@ int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter, | |||
735 | } | 723 | } |
736 | 724 | ||
737 | /* Disable a GbE interface */ | 725 | /* Disable a GbE interface */ |
738 | int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port) | 726 | int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter) |
739 | { | 727 | { |
740 | __u32 mac_cfg0; | 728 | __u32 mac_cfg0; |
729 | u32 port = physical_port[adapter->portnum]; | ||
741 | 730 | ||
742 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) | 731 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) |
743 | return -EINVAL; | 732 | return -EINVAL; |
744 | |||
745 | mac_cfg0 = 0; | 733 | mac_cfg0 = 0; |
746 | netxen_gb_soft_reset(mac_cfg0); | 734 | netxen_gb_soft_reset(mac_cfg0); |
747 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), | 735 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port), |
@@ -751,13 +739,13 @@ int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter, int port) | |||
751 | } | 739 | } |
752 | 740 | ||
753 | /* Disable an XG interface */ | 741 | /* Disable an XG interface */ |
754 | int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port) | 742 | int netxen_niu_disable_xg_port(struct netxen_adapter *adapter) |
755 | { | 743 | { |
756 | __u32 mac_cfg; | 744 | __u32 mac_cfg; |
745 | u32 port = physical_port[adapter->portnum]; | ||
757 | 746 | ||
758 | if (port != 0) | 747 | if (port != 0) |
759 | return -EINVAL; | 748 | return -EINVAL; |
760 | |||
761 | mac_cfg = 0; | 749 | mac_cfg = 0; |
762 | netxen_xg_soft_reset(mac_cfg); | 750 | netxen_xg_soft_reset(mac_cfg); |
763 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0, | 751 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_CONFIG_0, |
@@ -767,10 +755,11 @@ int netxen_niu_disable_xg_port(struct netxen_adapter *adapter, int port) | |||
767 | } | 755 | } |
768 | 756 | ||
769 | /* Set promiscuous mode for a GbE interface */ | 757 | /* Set promiscuous mode for a GbE interface */ |
770 | int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port, | 758 | int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, |
771 | netxen_niu_prom_mode_t mode) | 759 | netxen_niu_prom_mode_t mode) |
772 | { | 760 | { |
773 | __u32 reg; | 761 | __u32 reg; |
762 | u32 port = physical_port[adapter->portnum]; | ||
774 | 763 | ||
775 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) | 764 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) |
776 | return -EINVAL; | 765 | return -EINVAL; |
@@ -824,25 +813,50 @@ int netxen_niu_set_promiscuous_mode(struct netxen_adapter *adapter, int port, | |||
824 | * Set the MAC address for an XG port | 813 | * Set the MAC address for an XG port |
825 | * Note that the passed-in value must already be in network byte order. | 814 | * Note that the passed-in value must already be in network byte order. |
826 | */ | 815 | */ |
827 | int netxen_niu_xg_macaddr_set(struct netxen_port *port, | 816 | int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter, |
828 | netxen_ethernet_macaddr_t addr) | 817 | netxen_ethernet_macaddr_t addr) |
829 | { | 818 | { |
819 | int phy = physical_port[adapter->portnum]; | ||
830 | u8 temp[4]; | 820 | u8 temp[4]; |
831 | u32 val; | 821 | u32 val; |
832 | struct netxen_adapter *adapter = port->adapter; | 822 | |
823 | if ((phy < 0) || (phy > NETXEN_NIU_MAX_XG_PORTS)) | ||
824 | return -EIO; | ||
833 | 825 | ||
834 | temp[0] = temp[1] = 0; | 826 | temp[0] = temp[1] = 0; |
835 | memcpy(temp + 2, addr, 2); | 827 | switch (phy) { |
836 | val = le32_to_cpu(*(__le32 *)temp); | 828 | case 0: |
837 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, | 829 | memcpy(temp + 2, addr, 2); |
838 | &val, 4)) | 830 | val = le32_to_cpu(*(__le32 *)temp); |
831 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1, | ||
832 | &val, 4)) | ||
839 | return -EIO; | 833 | return -EIO; |
840 | 834 | ||
841 | memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); | 835 | memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); |
842 | val = le32_to_cpu(*(__le32 *)temp); | 836 | val = le32_to_cpu(*(__le32 *)temp); |
843 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, | 837 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI, |
844 | &val, 4)) | 838 | &val, 4)) |
839 | return -EIO; | ||
840 | break; | ||
841 | |||
842 | case 1: | ||
843 | memcpy(temp + 2, addr, 2); | ||
844 | val = le32_to_cpu(*(__le32 *)temp); | ||
845 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_1, | ||
846 | &val, 4)) | ||
847 | return -EIO; | ||
848 | |||
849 | memcpy(&temp, ((u8 *) addr) + 2, sizeof(__le32)); | ||
850 | val = le32_to_cpu(*(__le32 *)temp); | ||
851 | if (netxen_nic_hw_write_wx(adapter, NETXEN_NIU_XG1_STATION_ADDR_0_HI, | ||
852 | &val, 4)) | ||
845 | return -EIO; | 853 | return -EIO; |
854 | break; | ||
855 | |||
856 | default: | ||
857 | printk(KERN_ERR "Unknown port %d\n", phy); | ||
858 | break; | ||
859 | } | ||
846 | 860 | ||
847 | return 0; | 861 | return 0; |
848 | } | 862 | } |
@@ -851,9 +865,10 @@ int netxen_niu_xg_macaddr_set(struct netxen_port *port, | |||
851 | * Return the current station MAC address. | 865 | * Return the current station MAC address. |
852 | * Note that the passed-in value must already be in network byte order. | 866 | * Note that the passed-in value must already be in network byte order. |
853 | */ | 867 | */ |
854 | int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy, | 868 | int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, |
855 | netxen_ethernet_macaddr_t * addr) | 869 | netxen_ethernet_macaddr_t * addr) |
856 | { | 870 | { |
871 | int phy = physical_port[adapter->portnum]; | ||
857 | u32 stationhigh; | 872 | u32 stationhigh; |
858 | u32 stationlow; | 873 | u32 stationlow; |
859 | u8 val[8]; | 874 | u8 val[8]; |
@@ -878,21 +893,24 @@ int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter, int phy, | |||
878 | } | 893 | } |
879 | 894 | ||
880 | int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, | 895 | int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter, |
881 | int port, netxen_niu_prom_mode_t mode) | 896 | netxen_niu_prom_mode_t mode) |
882 | { | 897 | { |
883 | __u32 reg; | 898 | __u32 reg; |
899 | u32 port = physical_port[adapter->portnum]; | ||
884 | 900 | ||
885 | if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS)) | 901 | if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS)) |
886 | return -EINVAL; | 902 | return -EINVAL; |
887 | 903 | ||
888 | if (netxen_nic_hw_read_wx(adapter, NETXEN_NIU_XGE_CONFIG_1, ®, 4)) | 904 | if (netxen_nic_hw_read_wx(adapter, |
889 | return -EIO; | 905 | NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), ®, 4)) |
906 | return -EIO; | ||
890 | if (mode == NETXEN_NIU_PROMISC_MODE) | 907 | if (mode == NETXEN_NIU_PROMISC_MODE) |
891 | reg = (reg | 0x2000UL); | 908 | reg = (reg | 0x2000UL); |
892 | else | 909 | else |
893 | reg = (reg & ~0x2000UL); | 910 | reg = (reg & ~0x2000UL); |
894 | 911 | ||
895 | netxen_crb_writelit_adapter(adapter, NETXEN_NIU_XGE_CONFIG_1, reg); | 912 | netxen_crb_writelit_adapter(adapter, |
913 | NETXEN_NIU_XGE_CONFIG_1 + (0x10000 * port), reg); | ||
896 | 914 | ||
897 | return 0; | 915 | return 0; |
898 | } | 916 | } |
diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h index 0c7c94328b7f..9457fc7249c8 100644 --- a/drivers/net/netxen/netxen_nic_phan_reg.h +++ b/drivers/net/netxen/netxen_nic_phan_reg.h | |||
@@ -100,8 +100,21 @@ | |||
100 | 100 | ||
101 | #define CRB_CMD_PRODUCER_OFFSET_1 NETXEN_NIC_REG(0x1ac) | 101 | #define CRB_CMD_PRODUCER_OFFSET_1 NETXEN_NIC_REG(0x1ac) |
102 | #define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) | 102 | #define CRB_CMD_CONSUMER_OFFSET_1 NETXEN_NIC_REG(0x1b0) |
103 | #define CRB_CMD_PRODUCER_OFFSET_2 NETXEN_NIC_REG(0x1b8) | ||
104 | #define CRB_CMD_CONSUMER_OFFSET_2 NETXEN_NIC_REG(0x1bc) | ||
105 | |||
106 | // 1c0 to 1cc used for signature reg | ||
107 | #define CRB_CMD_PRODUCER_OFFSET_3 NETXEN_NIC_REG(0x1d0) | ||
108 | #define CRB_CMD_CONSUMER_OFFSET_3 NETXEN_NIC_REG(0x1d4) | ||
103 | #define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) | 109 | #define CRB_TEMP_STATE NETXEN_NIC_REG(0x1b4) |
104 | 110 | ||
111 | #define CRB_V2P_0 NETXEN_NIC_REG(0x290) | ||
112 | #define CRB_V2P_1 NETXEN_NIC_REG(0x294) | ||
113 | #define CRB_V2P_2 NETXEN_NIC_REG(0x298) | ||
114 | #define CRB_V2P_3 NETXEN_NIC_REG(0x29c) | ||
115 | #define CRB_V2P(port) (CRB_V2P_0+((port)*4)) | ||
116 | #define CRB_DRIVER_VERSION NETXEN_NIC_REG(0x2a0) | ||
117 | |||
105 | /* used for ethtool tests */ | 118 | /* used for ethtool tests */ |
106 | #define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) | 119 | #define CRB_SCRATCHPAD_TEST NETXEN_NIC_REG(0x280) |
107 | 120 | ||
@@ -139,128 +152,13 @@ struct netxen_recv_crb { | |||
139 | }; | 152 | }; |
140 | 153 | ||
141 | #if defined(DEFINE_GLOBAL_RECV_CRB) | 154 | #if defined(DEFINE_GLOBAL_RECV_CRB) |
142 | struct netxen_recv_crb recv_crb_registers[] = { | ||
143 | /* | ||
144 | * Instance 0. | ||
145 | */ | ||
146 | { | ||
147 | /* rcv_desc_crb: */ | ||
148 | { | ||
149 | { | ||
150 | /* crb_rcv_producer_offset: */ | ||
151 | NETXEN_NIC_REG(0x100), | ||
152 | /* crb_rcv_consumer_offset: */ | ||
153 | NETXEN_NIC_REG(0x104), | ||
154 | /* crb_gloablrcv_ring: */ | ||
155 | NETXEN_NIC_REG(0x108), | ||
156 | /* crb_rcv_ring_size */ | ||
157 | NETXEN_NIC_REG(0x10c), | ||
158 | |||
159 | }, | ||
160 | /* Jumbo frames */ | ||
161 | { | ||
162 | /* crb_rcv_producer_offset: */ | ||
163 | NETXEN_NIC_REG(0x110), | ||
164 | /* crb_rcv_consumer_offset: */ | ||
165 | NETXEN_NIC_REG(0x114), | ||
166 | /* crb_gloablrcv_ring: */ | ||
167 | NETXEN_NIC_REG(0x118), | ||
168 | /* crb_rcv_ring_size */ | ||
169 | NETXEN_NIC_REG(0x11c), | ||
170 | }, | ||
171 | /* LRO */ | ||
172 | { | ||
173 | /* crb_rcv_producer_offset: */ | ||
174 | NETXEN_NIC_REG(0x120), | ||
175 | /* crb_rcv_consumer_offset: */ | ||
176 | NETXEN_NIC_REG(0x124), | ||
177 | /* crb_gloablrcv_ring: */ | ||
178 | NETXEN_NIC_REG(0x128), | ||
179 | /* crb_rcv_ring_size */ | ||
180 | NETXEN_NIC_REG(0x12c), | ||
181 | } | ||
182 | }, | ||
183 | /* crb_rcvstatus_ring: */ | ||
184 | NETXEN_NIC_REG(0x130), | ||
185 | /* crb_rcv_status_producer: */ | ||
186 | NETXEN_NIC_REG(0x134), | ||
187 | /* crb_rcv_status_consumer: */ | ||
188 | NETXEN_NIC_REG(0x138), | ||
189 | /* crb_rcvpeg_state: */ | ||
190 | NETXEN_NIC_REG(0x13c), | ||
191 | /* crb_status_ring_size */ | ||
192 | NETXEN_NIC_REG(0x140), | ||
193 | |||
194 | }, | ||
195 | /* | ||
196 | * Instance 1, | ||
197 | */ | ||
198 | { | ||
199 | /* rcv_desc_crb: */ | ||
200 | { | ||
201 | { | ||
202 | /* crb_rcv_producer_offset: */ | ||
203 | NETXEN_NIC_REG(0x144), | ||
204 | /* crb_rcv_consumer_offset: */ | ||
205 | NETXEN_NIC_REG(0x148), | ||
206 | /* crb_globalrcv_ring: */ | ||
207 | NETXEN_NIC_REG(0x14c), | ||
208 | /* crb_rcv_ring_size */ | ||
209 | NETXEN_NIC_REG(0x150), | ||
210 | |||
211 | }, | ||
212 | /* Jumbo frames */ | ||
213 | { | ||
214 | /* crb_rcv_producer_offset: */ | ||
215 | NETXEN_NIC_REG(0x154), | ||
216 | /* crb_rcv_consumer_offset: */ | ||
217 | NETXEN_NIC_REG(0x158), | ||
218 | /* crb_globalrcv_ring: */ | ||
219 | NETXEN_NIC_REG(0x15c), | ||
220 | /* crb_rcv_ring_size */ | ||
221 | NETXEN_NIC_REG(0x160), | ||
222 | }, | ||
223 | /* LRO */ | ||
224 | { | ||
225 | /* crb_rcv_producer_offset: */ | ||
226 | NETXEN_NIC_REG(0x164), | ||
227 | /* crb_rcv_consumer_offset: */ | ||
228 | NETXEN_NIC_REG(0x168), | ||
229 | /* crb_globalrcv_ring: */ | ||
230 | NETXEN_NIC_REG(0x16c), | ||
231 | /* crb_rcv_ring_size */ | ||
232 | NETXEN_NIC_REG(0x170), | ||
233 | } | ||
234 | |||
235 | }, | ||
236 | /* crb_rcvstatus_ring: */ | ||
237 | NETXEN_NIC_REG(0x174), | ||
238 | /* crb_rcv_status_producer: */ | ||
239 | NETXEN_NIC_REG(0x178), | ||
240 | /* crb_rcv_status_consumer: */ | ||
241 | NETXEN_NIC_REG(0x17c), | ||
242 | /* crb_rcvpeg_state: */ | ||
243 | NETXEN_NIC_REG(0x180), | ||
244 | /* crb_status_ring_size */ | ||
245 | NETXEN_NIC_REG(0x184), | ||
246 | |||
247 | }, | ||
248 | }; | ||
249 | |||
250 | u64 ctx_addr_sig_regs[][3] = { | ||
251 | {NETXEN_NIC_REG(0x188), NETXEN_NIC_REG(0x18c), NETXEN_NIC_REG(0x1c0)}, | ||
252 | {NETXEN_NIC_REG(0x190), NETXEN_NIC_REG(0x194), NETXEN_NIC_REG(0x1c4)}, | ||
253 | {NETXEN_NIC_REG(0x198), NETXEN_NIC_REG(0x19c), NETXEN_NIC_REG(0x1c8)}, | ||
254 | {NETXEN_NIC_REG(0x1a0), NETXEN_NIC_REG(0x1a4), NETXEN_NIC_REG(0x1cc)} | ||
255 | }; | ||
256 | |||
257 | #else | 155 | #else |
258 | extern struct netxen_recv_crb recv_crb_registers[]; | 156 | extern struct netxen_recv_crb recv_crb_registers[]; |
259 | extern u64 ctx_addr_sig_regs[][3]; | 157 | extern u64 ctx_addr_sig_regs[][3]; |
260 | #define CRB_CTX_ADDR_REG_LO (ctx_addr_sig_regs[0][0]) | ||
261 | #define CRB_CTX_ADDR_REG_HI (ctx_addr_sig_regs[0][2]) | ||
262 | #define CRB_CTX_SIGNATURE_REG (ctx_addr_sig_regs[0][1]) | ||
263 | #endif /* DEFINE_GLOBAL_RECEIVE_CRB */ | 158 | #endif /* DEFINE_GLOBAL_RECEIVE_CRB */ |
159 | #define CRB_CTX_ADDR_REG_LO(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][0]) | ||
160 | #define CRB_CTX_ADDR_REG_HI(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][2]) | ||
161 | #define CRB_CTX_SIGNATURE_REG(FUNC_ID) (ctx_addr_sig_regs[FUNC_ID][1]) | ||
264 | 162 | ||
265 | /* | 163 | /* |
266 | * Temperature control. | 164 | * Temperature control. |
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index 0791360a6a66..9c171a7390e2 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c | |||
@@ -253,12 +253,12 @@ struct pcnet32_access { | |||
253 | * so the structure should be allocated using pci_alloc_consistent(). | 253 | * so the structure should be allocated using pci_alloc_consistent(). |
254 | */ | 254 | */ |
255 | struct pcnet32_private { | 255 | struct pcnet32_private { |
256 | struct pcnet32_init_block init_block; | 256 | struct pcnet32_init_block *init_block; |
257 | /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ | 257 | /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ |
258 | struct pcnet32_rx_head *rx_ring; | 258 | struct pcnet32_rx_head *rx_ring; |
259 | struct pcnet32_tx_head *tx_ring; | 259 | struct pcnet32_tx_head *tx_ring; |
260 | dma_addr_t dma_addr;/* DMA address of beginning of this | 260 | dma_addr_t init_dma_addr;/* DMA address of beginning of the init block, |
261 | object, returned by pci_alloc_consistent */ | 261 | returned by pci_alloc_consistent */ |
262 | struct pci_dev *pci_dev; | 262 | struct pci_dev *pci_dev; |
263 | const char *name; | 263 | const char *name; |
264 | /* The saved address of a sent-in-place packet/buffer, for skfree(). */ | 264 | /* The saved address of a sent-in-place packet/buffer, for skfree(). */ |
@@ -653,7 +653,7 @@ static void pcnet32_realloc_rx_ring(struct net_device *dev, | |||
653 | 653 | ||
654 | static void pcnet32_purge_rx_ring(struct net_device *dev) | 654 | static void pcnet32_purge_rx_ring(struct net_device *dev) |
655 | { | 655 | { |
656 | struct pcnet32_private *lp = dev->priv; | 656 | struct pcnet32_private *lp = netdev_priv(dev); |
657 | int i; | 657 | int i; |
658 | 658 | ||
659 | /* free all allocated skbuffs */ | 659 | /* free all allocated skbuffs */ |
@@ -681,7 +681,7 @@ static void pcnet32_poll_controller(struct net_device *dev) | |||
681 | 681 | ||
682 | static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 682 | static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
683 | { | 683 | { |
684 | struct pcnet32_private *lp = dev->priv; | 684 | struct pcnet32_private *lp = netdev_priv(dev); |
685 | unsigned long flags; | 685 | unsigned long flags; |
686 | int r = -EOPNOTSUPP; | 686 | int r = -EOPNOTSUPP; |
687 | 687 | ||
@@ -696,7 +696,7 @@ static int pcnet32_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
696 | 696 | ||
697 | static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | 697 | static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
698 | { | 698 | { |
699 | struct pcnet32_private *lp = dev->priv; | 699 | struct pcnet32_private *lp = netdev_priv(dev); |
700 | unsigned long flags; | 700 | unsigned long flags; |
701 | int r = -EOPNOTSUPP; | 701 | int r = -EOPNOTSUPP; |
702 | 702 | ||
@@ -711,7 +711,7 @@ static int pcnet32_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
711 | static void pcnet32_get_drvinfo(struct net_device *dev, | 711 | static void pcnet32_get_drvinfo(struct net_device *dev, |
712 | struct ethtool_drvinfo *info) | 712 | struct ethtool_drvinfo *info) |
713 | { | 713 | { |
714 | struct pcnet32_private *lp = dev->priv; | 714 | struct pcnet32_private *lp = netdev_priv(dev); |
715 | 715 | ||
716 | strcpy(info->driver, DRV_NAME); | 716 | strcpy(info->driver, DRV_NAME); |
717 | strcpy(info->version, DRV_VERSION); | 717 | strcpy(info->version, DRV_VERSION); |
@@ -723,7 +723,7 @@ static void pcnet32_get_drvinfo(struct net_device *dev, | |||
723 | 723 | ||
724 | static u32 pcnet32_get_link(struct net_device *dev) | 724 | static u32 pcnet32_get_link(struct net_device *dev) |
725 | { | 725 | { |
726 | struct pcnet32_private *lp = dev->priv; | 726 | struct pcnet32_private *lp = netdev_priv(dev); |
727 | unsigned long flags; | 727 | unsigned long flags; |
728 | int r; | 728 | int r; |
729 | 729 | ||
@@ -743,19 +743,19 @@ static u32 pcnet32_get_link(struct net_device *dev) | |||
743 | 743 | ||
744 | static u32 pcnet32_get_msglevel(struct net_device *dev) | 744 | static u32 pcnet32_get_msglevel(struct net_device *dev) |
745 | { | 745 | { |
746 | struct pcnet32_private *lp = dev->priv; | 746 | struct pcnet32_private *lp = netdev_priv(dev); |
747 | return lp->msg_enable; | 747 | return lp->msg_enable; |
748 | } | 748 | } |
749 | 749 | ||
750 | static void pcnet32_set_msglevel(struct net_device *dev, u32 value) | 750 | static void pcnet32_set_msglevel(struct net_device *dev, u32 value) |
751 | { | 751 | { |
752 | struct pcnet32_private *lp = dev->priv; | 752 | struct pcnet32_private *lp = netdev_priv(dev); |
753 | lp->msg_enable = value; | 753 | lp->msg_enable = value; |
754 | } | 754 | } |
755 | 755 | ||
756 | static int pcnet32_nway_reset(struct net_device *dev) | 756 | static int pcnet32_nway_reset(struct net_device *dev) |
757 | { | 757 | { |
758 | struct pcnet32_private *lp = dev->priv; | 758 | struct pcnet32_private *lp = netdev_priv(dev); |
759 | unsigned long flags; | 759 | unsigned long flags; |
760 | int r = -EOPNOTSUPP; | 760 | int r = -EOPNOTSUPP; |
761 | 761 | ||
@@ -770,7 +770,7 @@ static int pcnet32_nway_reset(struct net_device *dev) | |||
770 | static void pcnet32_get_ringparam(struct net_device *dev, | 770 | static void pcnet32_get_ringparam(struct net_device *dev, |
771 | struct ethtool_ringparam *ering) | 771 | struct ethtool_ringparam *ering) |
772 | { | 772 | { |
773 | struct pcnet32_private *lp = dev->priv; | 773 | struct pcnet32_private *lp = netdev_priv(dev); |
774 | 774 | ||
775 | ering->tx_max_pending = TX_MAX_RING_SIZE; | 775 | ering->tx_max_pending = TX_MAX_RING_SIZE; |
776 | ering->tx_pending = lp->tx_ring_size; | 776 | ering->tx_pending = lp->tx_ring_size; |
@@ -781,7 +781,7 @@ static void pcnet32_get_ringparam(struct net_device *dev, | |||
781 | static int pcnet32_set_ringparam(struct net_device *dev, | 781 | static int pcnet32_set_ringparam(struct net_device *dev, |
782 | struct ethtool_ringparam *ering) | 782 | struct ethtool_ringparam *ering) |
783 | { | 783 | { |
784 | struct pcnet32_private *lp = dev->priv; | 784 | struct pcnet32_private *lp = netdev_priv(dev); |
785 | unsigned long flags; | 785 | unsigned long flags; |
786 | unsigned int size; | 786 | unsigned int size; |
787 | ulong ioaddr = dev->base_addr; | 787 | ulong ioaddr = dev->base_addr; |
@@ -847,7 +847,7 @@ static int pcnet32_self_test_count(struct net_device *dev) | |||
847 | static void pcnet32_ethtool_test(struct net_device *dev, | 847 | static void pcnet32_ethtool_test(struct net_device *dev, |
848 | struct ethtool_test *test, u64 * data) | 848 | struct ethtool_test *test, u64 * data) |
849 | { | 849 | { |
850 | struct pcnet32_private *lp = dev->priv; | 850 | struct pcnet32_private *lp = netdev_priv(dev); |
851 | int rc; | 851 | int rc; |
852 | 852 | ||
853 | if (test->flags == ETH_TEST_FL_OFFLINE) { | 853 | if (test->flags == ETH_TEST_FL_OFFLINE) { |
@@ -868,7 +868,7 @@ static void pcnet32_ethtool_test(struct net_device *dev, | |||
868 | 868 | ||
869 | static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) | 869 | static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) |
870 | { | 870 | { |
871 | struct pcnet32_private *lp = dev->priv; | 871 | struct pcnet32_private *lp = netdev_priv(dev); |
872 | struct pcnet32_access *a = &lp->a; /* access to registers */ | 872 | struct pcnet32_access *a = &lp->a; /* access to registers */ |
873 | ulong ioaddr = dev->base_addr; /* card base I/O address */ | 873 | ulong ioaddr = dev->base_addr; /* card base I/O address */ |
874 | struct sk_buff *skb; /* sk buff */ | 874 | struct sk_buff *skb; /* sk buff */ |
@@ -1047,7 +1047,7 @@ static int pcnet32_loopback_test(struct net_device *dev, uint64_t * data1) | |||
1047 | 1047 | ||
1048 | static void pcnet32_led_blink_callback(struct net_device *dev) | 1048 | static void pcnet32_led_blink_callback(struct net_device *dev) |
1049 | { | 1049 | { |
1050 | struct pcnet32_private *lp = dev->priv; | 1050 | struct pcnet32_private *lp = netdev_priv(dev); |
1051 | struct pcnet32_access *a = &lp->a; | 1051 | struct pcnet32_access *a = &lp->a; |
1052 | ulong ioaddr = dev->base_addr; | 1052 | ulong ioaddr = dev->base_addr; |
1053 | unsigned long flags; | 1053 | unsigned long flags; |
@@ -1064,7 +1064,7 @@ static void pcnet32_led_blink_callback(struct net_device *dev) | |||
1064 | 1064 | ||
1065 | static int pcnet32_phys_id(struct net_device *dev, u32 data) | 1065 | static int pcnet32_phys_id(struct net_device *dev, u32 data) |
1066 | { | 1066 | { |
1067 | struct pcnet32_private *lp = dev->priv; | 1067 | struct pcnet32_private *lp = netdev_priv(dev); |
1068 | struct pcnet32_access *a = &lp->a; | 1068 | struct pcnet32_access *a = &lp->a; |
1069 | ulong ioaddr = dev->base_addr; | 1069 | ulong ioaddr = dev->base_addr; |
1070 | unsigned long flags; | 1070 | unsigned long flags; |
@@ -1109,7 +1109,7 @@ static int pcnet32_suspend(struct net_device *dev, unsigned long *flags, | |||
1109 | int can_sleep) | 1109 | int can_sleep) |
1110 | { | 1110 | { |
1111 | int csr5; | 1111 | int csr5; |
1112 | struct pcnet32_private *lp = dev->priv; | 1112 | struct pcnet32_private *lp = netdev_priv(dev); |
1113 | struct pcnet32_access *a = &lp->a; | 1113 | struct pcnet32_access *a = &lp->a; |
1114 | ulong ioaddr = dev->base_addr; | 1114 | ulong ioaddr = dev->base_addr; |
1115 | int ticks; | 1115 | int ticks; |
@@ -1257,7 +1257,7 @@ static void pcnet32_rx_entry(struct net_device *dev, | |||
1257 | 1257 | ||
1258 | static int pcnet32_rx(struct net_device *dev, int quota) | 1258 | static int pcnet32_rx(struct net_device *dev, int quota) |
1259 | { | 1259 | { |
1260 | struct pcnet32_private *lp = dev->priv; | 1260 | struct pcnet32_private *lp = netdev_priv(dev); |
1261 | int entry = lp->cur_rx & lp->rx_mod_mask; | 1261 | int entry = lp->cur_rx & lp->rx_mod_mask; |
1262 | struct pcnet32_rx_head *rxp = &lp->rx_ring[entry]; | 1262 | struct pcnet32_rx_head *rxp = &lp->rx_ring[entry]; |
1263 | int npackets = 0; | 1263 | int npackets = 0; |
@@ -1282,7 +1282,7 @@ static int pcnet32_rx(struct net_device *dev, int quota) | |||
1282 | 1282 | ||
1283 | static int pcnet32_tx(struct net_device *dev) | 1283 | static int pcnet32_tx(struct net_device *dev) |
1284 | { | 1284 | { |
1285 | struct pcnet32_private *lp = dev->priv; | 1285 | struct pcnet32_private *lp = netdev_priv(dev); |
1286 | unsigned int dirty_tx = lp->dirty_tx; | 1286 | unsigned int dirty_tx = lp->dirty_tx; |
1287 | int delta; | 1287 | int delta; |
1288 | int must_restart = 0; | 1288 | int must_restart = 0; |
@@ -1381,7 +1381,7 @@ static int pcnet32_tx(struct net_device *dev) | |||
1381 | #ifdef CONFIG_PCNET32_NAPI | 1381 | #ifdef CONFIG_PCNET32_NAPI |
1382 | static int pcnet32_poll(struct net_device *dev, int *budget) | 1382 | static int pcnet32_poll(struct net_device *dev, int *budget) |
1383 | { | 1383 | { |
1384 | struct pcnet32_private *lp = dev->priv; | 1384 | struct pcnet32_private *lp = netdev_priv(dev); |
1385 | int quota = min(dev->quota, *budget); | 1385 | int quota = min(dev->quota, *budget); |
1386 | unsigned long ioaddr = dev->base_addr; | 1386 | unsigned long ioaddr = dev->base_addr; |
1387 | unsigned long flags; | 1387 | unsigned long flags; |
@@ -1428,7 +1428,7 @@ static int pcnet32_poll(struct net_device *dev, int *budget) | |||
1428 | #define PCNET32_MAX_PHYS 32 | 1428 | #define PCNET32_MAX_PHYS 32 |
1429 | static int pcnet32_get_regs_len(struct net_device *dev) | 1429 | static int pcnet32_get_regs_len(struct net_device *dev) |
1430 | { | 1430 | { |
1431 | struct pcnet32_private *lp = dev->priv; | 1431 | struct pcnet32_private *lp = netdev_priv(dev); |
1432 | int j = lp->phycount * PCNET32_REGS_PER_PHY; | 1432 | int j = lp->phycount * PCNET32_REGS_PER_PHY; |
1433 | 1433 | ||
1434 | return ((PCNET32_NUM_REGS + j) * sizeof(u16)); | 1434 | return ((PCNET32_NUM_REGS + j) * sizeof(u16)); |
@@ -1439,7 +1439,7 @@ static void pcnet32_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
1439 | { | 1439 | { |
1440 | int i, csr0; | 1440 | int i, csr0; |
1441 | u16 *buff = ptr; | 1441 | u16 *buff = ptr; |
1442 | struct pcnet32_private *lp = dev->priv; | 1442 | struct pcnet32_private *lp = netdev_priv(dev); |
1443 | struct pcnet32_access *a = &lp->a; | 1443 | struct pcnet32_access *a = &lp->a; |
1444 | ulong ioaddr = dev->base_addr; | 1444 | ulong ioaddr = dev->base_addr; |
1445 | unsigned long flags; | 1445 | unsigned long flags; |
@@ -1592,7 +1592,6 @@ static int __devinit | |||
1592 | pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) | 1592 | pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) |
1593 | { | 1593 | { |
1594 | struct pcnet32_private *lp; | 1594 | struct pcnet32_private *lp; |
1595 | dma_addr_t lp_dma_addr; | ||
1596 | int i, media; | 1595 | int i, media; |
1597 | int fdx, mii, fset, dxsuflo; | 1596 | int fdx, mii, fset, dxsuflo; |
1598 | int chip_version; | 1597 | int chip_version; |
@@ -1714,7 +1713,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) | |||
1714 | dxsuflo = 1; | 1713 | dxsuflo = 1; |
1715 | } | 1714 | } |
1716 | 1715 | ||
1717 | dev = alloc_etherdev(0); | 1716 | dev = alloc_etherdev(sizeof(*lp)); |
1718 | if (!dev) { | 1717 | if (!dev) { |
1719 | if (pcnet32_debug & NETIF_MSG_PROBE) | 1718 | if (pcnet32_debug & NETIF_MSG_PROBE) |
1720 | printk(KERN_ERR PFX "Memory allocation failed.\n"); | 1719 | printk(KERN_ERR PFX "Memory allocation failed.\n"); |
@@ -1805,25 +1804,22 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) | |||
1805 | } | 1804 | } |
1806 | 1805 | ||
1807 | dev->base_addr = ioaddr; | 1806 | dev->base_addr = ioaddr; |
1807 | lp = netdev_priv(dev); | ||
1808 | /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ | 1808 | /* pci_alloc_consistent returns page-aligned memory, so we do not have to check the alignment */ |
1809 | if ((lp = | 1809 | if ((lp->init_block = |
1810 | pci_alloc_consistent(pdev, sizeof(*lp), &lp_dma_addr)) == NULL) { | 1810 | pci_alloc_consistent(pdev, sizeof(*lp->init_block), &lp->init_dma_addr)) == NULL) { |
1811 | if (pcnet32_debug & NETIF_MSG_PROBE) | 1811 | if (pcnet32_debug & NETIF_MSG_PROBE) |
1812 | printk(KERN_ERR PFX | 1812 | printk(KERN_ERR PFX |
1813 | "Consistent memory allocation failed.\n"); | 1813 | "Consistent memory allocation failed.\n"); |
1814 | ret = -ENOMEM; | 1814 | ret = -ENOMEM; |
1815 | goto err_free_netdev; | 1815 | goto err_free_netdev; |
1816 | } | 1816 | } |
1817 | |||
1818 | memset(lp, 0, sizeof(*lp)); | ||
1819 | lp->dma_addr = lp_dma_addr; | ||
1820 | lp->pci_dev = pdev; | 1817 | lp->pci_dev = pdev; |
1821 | 1818 | ||
1822 | spin_lock_init(&lp->lock); | 1819 | spin_lock_init(&lp->lock); |
1823 | 1820 | ||
1824 | SET_MODULE_OWNER(dev); | 1821 | SET_MODULE_OWNER(dev); |
1825 | SET_NETDEV_DEV(dev, &pdev->dev); | 1822 | SET_NETDEV_DEV(dev, &pdev->dev); |
1826 | dev->priv = lp; | ||
1827 | lp->name = chipname; | 1823 | lp->name = chipname; |
1828 | lp->shared_irq = shared; | 1824 | lp->shared_irq = shared; |
1829 | lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ | 1825 | lp->tx_ring_size = TX_RING_SIZE; /* default tx ring size */ |
@@ -1870,23 +1866,21 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) | |||
1870 | && dev->dev_addr[2] == 0x75) | 1866 | && dev->dev_addr[2] == 0x75) |
1871 | lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; | 1867 | lp->options = PCNET32_PORT_FD | PCNET32_PORT_GPSI; |
1872 | 1868 | ||
1873 | lp->init_block.mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ | 1869 | lp->init_block->mode = le16_to_cpu(0x0003); /* Disable Rx and Tx. */ |
1874 | lp->init_block.tlen_rlen = | 1870 | lp->init_block->tlen_rlen = |
1875 | le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); | 1871 | le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); |
1876 | for (i = 0; i < 6; i++) | 1872 | for (i = 0; i < 6; i++) |
1877 | lp->init_block.phys_addr[i] = dev->dev_addr[i]; | 1873 | lp->init_block->phys_addr[i] = dev->dev_addr[i]; |
1878 | lp->init_block.filter[0] = 0x00000000; | 1874 | lp->init_block->filter[0] = 0x00000000; |
1879 | lp->init_block.filter[1] = 0x00000000; | 1875 | lp->init_block->filter[1] = 0x00000000; |
1880 | lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); | 1876 | lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); |
1881 | lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); | 1877 | lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); |
1882 | 1878 | ||
1883 | /* switch pcnet32 to 32bit mode */ | 1879 | /* switch pcnet32 to 32bit mode */ |
1884 | a->write_bcr(ioaddr, 20, 2); | 1880 | a->write_bcr(ioaddr, 20, 2); |
1885 | 1881 | ||
1886 | a->write_csr(ioaddr, 1, (lp->dma_addr + offsetof(struct pcnet32_private, | 1882 | a->write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff)); |
1887 | init_block)) & 0xffff); | 1883 | a->write_csr(ioaddr, 2, (lp->init_dma_addr >> 16)); |
1888 | a->write_csr(ioaddr, 2, (lp->dma_addr + offsetof(struct pcnet32_private, | ||
1889 | init_block)) >> 16); | ||
1890 | 1884 | ||
1891 | if (pdev) { /* use the IRQ provided by PCI */ | 1885 | if (pdev) { /* use the IRQ provided by PCI */ |
1892 | dev->irq = pdev->irq; | 1886 | dev->irq = pdev->irq; |
@@ -1992,7 +1986,8 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) | |||
1992 | err_free_ring: | 1986 | err_free_ring: |
1993 | pcnet32_free_ring(dev); | 1987 | pcnet32_free_ring(dev); |
1994 | err_free_consistent: | 1988 | err_free_consistent: |
1995 | pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); | 1989 | pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), |
1990 | lp->init_block, lp->init_dma_addr); | ||
1996 | err_free_netdev: | 1991 | err_free_netdev: |
1997 | free_netdev(dev); | 1992 | free_netdev(dev); |
1998 | err_release_region: | 1993 | err_release_region: |
@@ -2003,7 +1998,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) | |||
2003 | /* if any allocation fails, caller must also call pcnet32_free_ring */ | 1998 | /* if any allocation fails, caller must also call pcnet32_free_ring */ |
2004 | static int pcnet32_alloc_ring(struct net_device *dev, char *name) | 1999 | static int pcnet32_alloc_ring(struct net_device *dev, char *name) |
2005 | { | 2000 | { |
2006 | struct pcnet32_private *lp = dev->priv; | 2001 | struct pcnet32_private *lp = netdev_priv(dev); |
2007 | 2002 | ||
2008 | lp->tx_ring = pci_alloc_consistent(lp->pci_dev, | 2003 | lp->tx_ring = pci_alloc_consistent(lp->pci_dev, |
2009 | sizeof(struct pcnet32_tx_head) * | 2004 | sizeof(struct pcnet32_tx_head) * |
@@ -2070,7 +2065,7 @@ static int pcnet32_alloc_ring(struct net_device *dev, char *name) | |||
2070 | 2065 | ||
2071 | static void pcnet32_free_ring(struct net_device *dev) | 2066 | static void pcnet32_free_ring(struct net_device *dev) |
2072 | { | 2067 | { |
2073 | struct pcnet32_private *lp = dev->priv; | 2068 | struct pcnet32_private *lp = netdev_priv(dev); |
2074 | 2069 | ||
2075 | kfree(lp->tx_skbuff); | 2070 | kfree(lp->tx_skbuff); |
2076 | lp->tx_skbuff = NULL; | 2071 | lp->tx_skbuff = NULL; |
@@ -2103,7 +2098,7 @@ static void pcnet32_free_ring(struct net_device *dev) | |||
2103 | 2098 | ||
2104 | static int pcnet32_open(struct net_device *dev) | 2099 | static int pcnet32_open(struct net_device *dev) |
2105 | { | 2100 | { |
2106 | struct pcnet32_private *lp = dev->priv; | 2101 | struct pcnet32_private *lp = netdev_priv(dev); |
2107 | unsigned long ioaddr = dev->base_addr; | 2102 | unsigned long ioaddr = dev->base_addr; |
2108 | u16 val; | 2103 | u16 val; |
2109 | int i; | 2104 | int i; |
@@ -2134,8 +2129,7 @@ static int pcnet32_open(struct net_device *dev) | |||
2134 | "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", | 2129 | "%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", |
2135 | dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr), | 2130 | dev->name, dev->irq, (u32) (lp->tx_ring_dma_addr), |
2136 | (u32) (lp->rx_ring_dma_addr), | 2131 | (u32) (lp->rx_ring_dma_addr), |
2137 | (u32) (lp->dma_addr + | 2132 | (u32) (lp->init_dma_addr)); |
2138 | offsetof(struct pcnet32_private, init_block))); | ||
2139 | 2133 | ||
2140 | /* set/reset autoselect bit */ | 2134 | /* set/reset autoselect bit */ |
2141 | val = lp->a.read_bcr(ioaddr, 2) & ~2; | 2135 | val = lp->a.read_bcr(ioaddr, 2) & ~2; |
@@ -2274,7 +2268,7 @@ static int pcnet32_open(struct net_device *dev) | |||
2274 | } | 2268 | } |
2275 | #endif | 2269 | #endif |
2276 | 2270 | ||
2277 | lp->init_block.mode = | 2271 | lp->init_block->mode = |
2278 | le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); | 2272 | le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); |
2279 | pcnet32_load_multicast(dev); | 2273 | pcnet32_load_multicast(dev); |
2280 | 2274 | ||
@@ -2284,12 +2278,8 @@ static int pcnet32_open(struct net_device *dev) | |||
2284 | } | 2278 | } |
2285 | 2279 | ||
2286 | /* Re-initialize the PCNET32, and start it when done. */ | 2280 | /* Re-initialize the PCNET32, and start it when done. */ |
2287 | lp->a.write_csr(ioaddr, 1, (lp->dma_addr + | 2281 | lp->a.write_csr(ioaddr, 1, (lp->init_dma_addr & 0xffff)); |
2288 | offsetof(struct pcnet32_private, | 2282 | lp->a.write_csr(ioaddr, 2, (lp->init_dma_addr >> 16)); |
2289 | init_block)) & 0xffff); | ||
2290 | lp->a.write_csr(ioaddr, 2, | ||
2291 | (lp->dma_addr + | ||
2292 | offsetof(struct pcnet32_private, init_block)) >> 16); | ||
2293 | 2283 | ||
2294 | lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */ | 2284 | lp->a.write_csr(ioaddr, CSR4, 0x0915); /* auto tx pad */ |
2295 | lp->a.write_csr(ioaddr, CSR0, CSR0_INIT); | 2285 | lp->a.write_csr(ioaddr, CSR0, CSR0_INIT); |
@@ -2316,8 +2306,7 @@ static int pcnet32_open(struct net_device *dev) | |||
2316 | printk(KERN_DEBUG | 2306 | printk(KERN_DEBUG |
2317 | "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", | 2307 | "%s: pcnet32 open after %d ticks, init block %#x csr0 %4.4x.\n", |
2318 | dev->name, i, | 2308 | dev->name, i, |
2319 | (u32) (lp->dma_addr + | 2309 | (u32) (lp->init_dma_addr), |
2320 | offsetof(struct pcnet32_private, init_block)), | ||
2321 | lp->a.read_csr(ioaddr, CSR0)); | 2310 | lp->a.read_csr(ioaddr, CSR0)); |
2322 | 2311 | ||
2323 | spin_unlock_irqrestore(&lp->lock, flags); | 2312 | spin_unlock_irqrestore(&lp->lock, flags); |
@@ -2355,7 +2344,7 @@ static int pcnet32_open(struct net_device *dev) | |||
2355 | 2344 | ||
2356 | static void pcnet32_purge_tx_ring(struct net_device *dev) | 2345 | static void pcnet32_purge_tx_ring(struct net_device *dev) |
2357 | { | 2346 | { |
2358 | struct pcnet32_private *lp = dev->priv; | 2347 | struct pcnet32_private *lp = netdev_priv(dev); |
2359 | int i; | 2348 | int i; |
2360 | 2349 | ||
2361 | for (i = 0; i < lp->tx_ring_size; i++) { | 2350 | for (i = 0; i < lp->tx_ring_size; i++) { |
@@ -2375,7 +2364,7 @@ static void pcnet32_purge_tx_ring(struct net_device *dev) | |||
2375 | /* Initialize the PCNET32 Rx and Tx rings. */ | 2364 | /* Initialize the PCNET32 Rx and Tx rings. */ |
2376 | static int pcnet32_init_ring(struct net_device *dev) | 2365 | static int pcnet32_init_ring(struct net_device *dev) |
2377 | { | 2366 | { |
2378 | struct pcnet32_private *lp = dev->priv; | 2367 | struct pcnet32_private *lp = netdev_priv(dev); |
2379 | int i; | 2368 | int i; |
2380 | 2369 | ||
2381 | lp->tx_full = 0; | 2370 | lp->tx_full = 0; |
@@ -2417,12 +2406,12 @@ static int pcnet32_init_ring(struct net_device *dev) | |||
2417 | lp->tx_dma_addr[i] = 0; | 2406 | lp->tx_dma_addr[i] = 0; |
2418 | } | 2407 | } |
2419 | 2408 | ||
2420 | lp->init_block.tlen_rlen = | 2409 | lp->init_block->tlen_rlen = |
2421 | le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); | 2410 | le16_to_cpu(lp->tx_len_bits | lp->rx_len_bits); |
2422 | for (i = 0; i < 6; i++) | 2411 | for (i = 0; i < 6; i++) |
2423 | lp->init_block.phys_addr[i] = dev->dev_addr[i]; | 2412 | lp->init_block->phys_addr[i] = dev->dev_addr[i]; |
2424 | lp->init_block.rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); | 2413 | lp->init_block->rx_ring = (u32) le32_to_cpu(lp->rx_ring_dma_addr); |
2425 | lp->init_block.tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); | 2414 | lp->init_block->tx_ring = (u32) le32_to_cpu(lp->tx_ring_dma_addr); |
2426 | wmb(); /* Make sure all changes are visible */ | 2415 | wmb(); /* Make sure all changes are visible */ |
2427 | return 0; | 2416 | return 0; |
2428 | } | 2417 | } |
@@ -2433,7 +2422,7 @@ static int pcnet32_init_ring(struct net_device *dev) | |||
2433 | */ | 2422 | */ |
2434 | static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) | 2423 | static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) |
2435 | { | 2424 | { |
2436 | struct pcnet32_private *lp = dev->priv; | 2425 | struct pcnet32_private *lp = netdev_priv(dev); |
2437 | unsigned long ioaddr = dev->base_addr; | 2426 | unsigned long ioaddr = dev->base_addr; |
2438 | int i; | 2427 | int i; |
2439 | 2428 | ||
@@ -2463,7 +2452,7 @@ static void pcnet32_restart(struct net_device *dev, unsigned int csr0_bits) | |||
2463 | 2452 | ||
2464 | static void pcnet32_tx_timeout(struct net_device *dev) | 2453 | static void pcnet32_tx_timeout(struct net_device *dev) |
2465 | { | 2454 | { |
2466 | struct pcnet32_private *lp = dev->priv; | 2455 | struct pcnet32_private *lp = netdev_priv(dev); |
2467 | unsigned long ioaddr = dev->base_addr, flags; | 2456 | unsigned long ioaddr = dev->base_addr, flags; |
2468 | 2457 | ||
2469 | spin_lock_irqsave(&lp->lock, flags); | 2458 | spin_lock_irqsave(&lp->lock, flags); |
@@ -2504,7 +2493,7 @@ static void pcnet32_tx_timeout(struct net_device *dev) | |||
2504 | 2493 | ||
2505 | static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) | 2494 | static int pcnet32_start_xmit(struct sk_buff *skb, struct net_device *dev) |
2506 | { | 2495 | { |
2507 | struct pcnet32_private *lp = dev->priv; | 2496 | struct pcnet32_private *lp = netdev_priv(dev); |
2508 | unsigned long ioaddr = dev->base_addr; | 2497 | unsigned long ioaddr = dev->base_addr; |
2509 | u16 status; | 2498 | u16 status; |
2510 | int entry; | 2499 | int entry; |
@@ -2569,7 +2558,7 @@ pcnet32_interrupt(int irq, void *dev_id) | |||
2569 | int boguscnt = max_interrupt_work; | 2558 | int boguscnt = max_interrupt_work; |
2570 | 2559 | ||
2571 | ioaddr = dev->base_addr; | 2560 | ioaddr = dev->base_addr; |
2572 | lp = dev->priv; | 2561 | lp = netdev_priv(dev); |
2573 | 2562 | ||
2574 | spin_lock(&lp->lock); | 2563 | spin_lock(&lp->lock); |
2575 | 2564 | ||
@@ -2651,7 +2640,7 @@ pcnet32_interrupt(int irq, void *dev_id) | |||
2651 | static int pcnet32_close(struct net_device *dev) | 2640 | static int pcnet32_close(struct net_device *dev) |
2652 | { | 2641 | { |
2653 | unsigned long ioaddr = dev->base_addr; | 2642 | unsigned long ioaddr = dev->base_addr; |
2654 | struct pcnet32_private *lp = dev->priv; | 2643 | struct pcnet32_private *lp = netdev_priv(dev); |
2655 | unsigned long flags; | 2644 | unsigned long flags; |
2656 | 2645 | ||
2657 | del_timer_sync(&lp->watchdog_timer); | 2646 | del_timer_sync(&lp->watchdog_timer); |
@@ -2692,7 +2681,7 @@ static int pcnet32_close(struct net_device *dev) | |||
2692 | 2681 | ||
2693 | static struct net_device_stats *pcnet32_get_stats(struct net_device *dev) | 2682 | static struct net_device_stats *pcnet32_get_stats(struct net_device *dev) |
2694 | { | 2683 | { |
2695 | struct pcnet32_private *lp = dev->priv; | 2684 | struct pcnet32_private *lp = netdev_priv(dev); |
2696 | unsigned long ioaddr = dev->base_addr; | 2685 | unsigned long ioaddr = dev->base_addr; |
2697 | unsigned long flags; | 2686 | unsigned long flags; |
2698 | 2687 | ||
@@ -2706,8 +2695,8 @@ static struct net_device_stats *pcnet32_get_stats(struct net_device *dev) | |||
2706 | /* taken from the sunlance driver, which it took from the depca driver */ | 2695 | /* taken from the sunlance driver, which it took from the depca driver */ |
2707 | static void pcnet32_load_multicast(struct net_device *dev) | 2696 | static void pcnet32_load_multicast(struct net_device *dev) |
2708 | { | 2697 | { |
2709 | struct pcnet32_private *lp = dev->priv; | 2698 | struct pcnet32_private *lp = netdev_priv(dev); |
2710 | volatile struct pcnet32_init_block *ib = &lp->init_block; | 2699 | volatile struct pcnet32_init_block *ib = lp->init_block; |
2711 | volatile u16 *mcast_table = (u16 *) & ib->filter; | 2700 | volatile u16 *mcast_table = (u16 *) & ib->filter; |
2712 | struct dev_mc_list *dmi = dev->mc_list; | 2701 | struct dev_mc_list *dmi = dev->mc_list; |
2713 | unsigned long ioaddr = dev->base_addr; | 2702 | unsigned long ioaddr = dev->base_addr; |
@@ -2756,7 +2745,7 @@ static void pcnet32_load_multicast(struct net_device *dev) | |||
2756 | static void pcnet32_set_multicast_list(struct net_device *dev) | 2745 | static void pcnet32_set_multicast_list(struct net_device *dev) |
2757 | { | 2746 | { |
2758 | unsigned long ioaddr = dev->base_addr, flags; | 2747 | unsigned long ioaddr = dev->base_addr, flags; |
2759 | struct pcnet32_private *lp = dev->priv; | 2748 | struct pcnet32_private *lp = netdev_priv(dev); |
2760 | int csr15, suspended; | 2749 | int csr15, suspended; |
2761 | 2750 | ||
2762 | spin_lock_irqsave(&lp->lock, flags); | 2751 | spin_lock_irqsave(&lp->lock, flags); |
@@ -2767,12 +2756,12 @@ static void pcnet32_set_multicast_list(struct net_device *dev) | |||
2767 | if (netif_msg_hw(lp)) | 2756 | if (netif_msg_hw(lp)) |
2768 | printk(KERN_INFO "%s: Promiscuous mode enabled.\n", | 2757 | printk(KERN_INFO "%s: Promiscuous mode enabled.\n", |
2769 | dev->name); | 2758 | dev->name); |
2770 | lp->init_block.mode = | 2759 | lp->init_block->mode = |
2771 | le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << | 2760 | le16_to_cpu(0x8000 | (lp->options & PCNET32_PORT_PORTSEL) << |
2772 | 7); | 2761 | 7); |
2773 | lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000); | 2762 | lp->a.write_csr(ioaddr, CSR15, csr15 | 0x8000); |
2774 | } else { | 2763 | } else { |
2775 | lp->init_block.mode = | 2764 | lp->init_block->mode = |
2776 | le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); | 2765 | le16_to_cpu((lp->options & PCNET32_PORT_PORTSEL) << 7); |
2777 | lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff); | 2766 | lp->a.write_csr(ioaddr, CSR15, csr15 & 0x7fff); |
2778 | pcnet32_load_multicast(dev); | 2767 | pcnet32_load_multicast(dev); |
@@ -2795,7 +2784,7 @@ static void pcnet32_set_multicast_list(struct net_device *dev) | |||
2795 | /* This routine assumes that the lp->lock is held */ | 2784 | /* This routine assumes that the lp->lock is held */ |
2796 | static int mdio_read(struct net_device *dev, int phy_id, int reg_num) | 2785 | static int mdio_read(struct net_device *dev, int phy_id, int reg_num) |
2797 | { | 2786 | { |
2798 | struct pcnet32_private *lp = dev->priv; | 2787 | struct pcnet32_private *lp = netdev_priv(dev); |
2799 | unsigned long ioaddr = dev->base_addr; | 2788 | unsigned long ioaddr = dev->base_addr; |
2800 | u16 val_out; | 2789 | u16 val_out; |
2801 | 2790 | ||
@@ -2811,7 +2800,7 @@ static int mdio_read(struct net_device *dev, int phy_id, int reg_num) | |||
2811 | /* This routine assumes that the lp->lock is held */ | 2800 | /* This routine assumes that the lp->lock is held */ |
2812 | static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) | 2801 | static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) |
2813 | { | 2802 | { |
2814 | struct pcnet32_private *lp = dev->priv; | 2803 | struct pcnet32_private *lp = netdev_priv(dev); |
2815 | unsigned long ioaddr = dev->base_addr; | 2804 | unsigned long ioaddr = dev->base_addr; |
2816 | 2805 | ||
2817 | if (!lp->mii) | 2806 | if (!lp->mii) |
@@ -2823,7 +2812,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int reg_num, int val) | |||
2823 | 2812 | ||
2824 | static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | 2813 | static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
2825 | { | 2814 | { |
2826 | struct pcnet32_private *lp = dev->priv; | 2815 | struct pcnet32_private *lp = netdev_priv(dev); |
2827 | int rc; | 2816 | int rc; |
2828 | unsigned long flags; | 2817 | unsigned long flags; |
2829 | 2818 | ||
@@ -2841,7 +2830,7 @@ static int pcnet32_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | |||
2841 | 2830 | ||
2842 | static int pcnet32_check_otherphy(struct net_device *dev) | 2831 | static int pcnet32_check_otherphy(struct net_device *dev) |
2843 | { | 2832 | { |
2844 | struct pcnet32_private *lp = dev->priv; | 2833 | struct pcnet32_private *lp = netdev_priv(dev); |
2845 | struct mii_if_info mii = lp->mii_if; | 2834 | struct mii_if_info mii = lp->mii_if; |
2846 | u16 bmcr; | 2835 | u16 bmcr; |
2847 | int i; | 2836 | int i; |
@@ -2888,7 +2877,7 @@ static int pcnet32_check_otherphy(struct net_device *dev) | |||
2888 | 2877 | ||
2889 | static void pcnet32_check_media(struct net_device *dev, int verbose) | 2878 | static void pcnet32_check_media(struct net_device *dev, int verbose) |
2890 | { | 2879 | { |
2891 | struct pcnet32_private *lp = dev->priv; | 2880 | struct pcnet32_private *lp = netdev_priv(dev); |
2892 | int curr_link; | 2881 | int curr_link; |
2893 | int prev_link = netif_carrier_ok(dev) ? 1 : 0; | 2882 | int prev_link = netif_carrier_ok(dev) ? 1 : 0; |
2894 | u32 bcr9; | 2883 | u32 bcr9; |
@@ -2944,7 +2933,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose) | |||
2944 | 2933 | ||
2945 | static void pcnet32_watchdog(struct net_device *dev) | 2934 | static void pcnet32_watchdog(struct net_device *dev) |
2946 | { | 2935 | { |
2947 | struct pcnet32_private *lp = dev->priv; | 2936 | struct pcnet32_private *lp = netdev_priv(dev); |
2948 | unsigned long flags; | 2937 | unsigned long flags; |
2949 | 2938 | ||
2950 | /* Print the link status if it has changed */ | 2939 | /* Print the link status if it has changed */ |
@@ -2960,12 +2949,13 @@ static void __devexit pcnet32_remove_one(struct pci_dev *pdev) | |||
2960 | struct net_device *dev = pci_get_drvdata(pdev); | 2949 | struct net_device *dev = pci_get_drvdata(pdev); |
2961 | 2950 | ||
2962 | if (dev) { | 2951 | if (dev) { |
2963 | struct pcnet32_private *lp = dev->priv; | 2952 | struct pcnet32_private *lp = netdev_priv(dev); |
2964 | 2953 | ||
2965 | unregister_netdev(dev); | 2954 | unregister_netdev(dev); |
2966 | pcnet32_free_ring(dev); | 2955 | pcnet32_free_ring(dev); |
2967 | release_region(dev->base_addr, PCNET32_TOTAL_SIZE); | 2956 | release_region(dev->base_addr, PCNET32_TOTAL_SIZE); |
2968 | pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); | 2957 | pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), |
2958 | lp->init_block, lp->init_dma_addr); | ||
2969 | free_netdev(dev); | 2959 | free_netdev(dev); |
2970 | pci_disable_device(pdev); | 2960 | pci_disable_device(pdev); |
2971 | pci_set_drvdata(pdev, NULL); | 2961 | pci_set_drvdata(pdev, NULL); |
@@ -3040,12 +3030,13 @@ static void __exit pcnet32_cleanup_module(void) | |||
3040 | struct net_device *next_dev; | 3030 | struct net_device *next_dev; |
3041 | 3031 | ||
3042 | while (pcnet32_dev) { | 3032 | while (pcnet32_dev) { |
3043 | struct pcnet32_private *lp = pcnet32_dev->priv; | 3033 | struct pcnet32_private *lp = netdev_priv(pcnet32_dev); |
3044 | next_dev = lp->next; | 3034 | next_dev = lp->next; |
3045 | unregister_netdev(pcnet32_dev); | 3035 | unregister_netdev(pcnet32_dev); |
3046 | pcnet32_free_ring(pcnet32_dev); | 3036 | pcnet32_free_ring(pcnet32_dev); |
3047 | release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); | 3037 | release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); |
3048 | pci_free_consistent(lp->pci_dev, sizeof(*lp), lp, lp->dma_addr); | 3038 | pci_free_consistent(lp->pci_dev, sizeof(*lp->init_block), |
3039 | lp->init_block, lp->init_dma_addr); | ||
3049 | free_netdev(pcnet32_dev); | 3040 | free_netdev(pcnet32_dev); |
3050 | pcnet32_dev = next_dev; | 3041 | pcnet32_dev = next_dev; |
3051 | } | 3042 | } |
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index b31ce278bf35..fc4aee96cdfd 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c | |||
@@ -35,10 +35,14 @@ | |||
35 | #include <asm/irq.h> | 35 | #include <asm/irq.h> |
36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
37 | 37 | ||
38 | /* mdiobus_register | 38 | /** |
39 | * mdiobus_register - bring up all the PHYs on a given bus and attach them to bus | ||
40 | * @bus: target mii_bus | ||
39 | * | 41 | * |
40 | * description: Called by a bus driver to bring up all the PHYs | 42 | * Description: Called by a bus driver to bring up all the PHYs |
41 | * on a given bus, and attach them to the bus | 43 | * on a given bus, and attach them to the bus. |
44 | * | ||
45 | * Returns 0 on success or < 0 on error. | ||
42 | */ | 46 | */ |
43 | int mdiobus_register(struct mii_bus *bus) | 47 | int mdiobus_register(struct mii_bus *bus) |
44 | { | 48 | { |
@@ -114,10 +118,13 @@ void mdiobus_unregister(struct mii_bus *bus) | |||
114 | } | 118 | } |
115 | EXPORT_SYMBOL(mdiobus_unregister); | 119 | EXPORT_SYMBOL(mdiobus_unregister); |
116 | 120 | ||
117 | /* mdio_bus_match | 121 | /** |
122 | * mdio_bus_match - determine if given PHY driver supports the given PHY device | ||
123 | * @dev: target PHY device | ||
124 | * @drv: given PHY driver | ||
118 | * | 125 | * |
119 | * description: Given a PHY device, and a PHY driver, return 1 if | 126 | * Description: Given a PHY device, and a PHY driver, return 1 if |
120 | * the driver supports the device. Otherwise, return 0 | 127 | * the driver supports the device. Otherwise, return 0. |
121 | */ | 128 | */ |
122 | static int mdio_bus_match(struct device *dev, struct device_driver *drv) | 129 | static int mdio_bus_match(struct device *dev, struct device_driver *drv) |
123 | { | 130 | { |
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index c94a1fb3a4be..eed433d6056a 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c | |||
@@ -39,7 +39,9 @@ | |||
39 | #include <asm/irq.h> | 39 | #include <asm/irq.h> |
40 | #include <asm/uaccess.h> | 40 | #include <asm/uaccess.h> |
41 | 41 | ||
42 | /* Convenience function to print out the current phy status | 42 | /** |
43 | * phy_print_status - Convenience function to print out the current phy status | ||
44 | * @phydev: the phy_device struct | ||
43 | */ | 45 | */ |
44 | void phy_print_status(struct phy_device *phydev) | 46 | void phy_print_status(struct phy_device *phydev) |
45 | { | 47 | { |
@@ -55,10 +57,15 @@ void phy_print_status(struct phy_device *phydev) | |||
55 | EXPORT_SYMBOL(phy_print_status); | 57 | EXPORT_SYMBOL(phy_print_status); |
56 | 58 | ||
57 | 59 | ||
58 | /* Convenience functions for reading/writing a given PHY | 60 | /** |
59 | * register. They MUST NOT be called from interrupt context, | 61 | * phy_read - Convenience function for reading a given PHY register |
62 | * @phydev: the phy_device struct | ||
63 | * @regnum: register number to read | ||
64 | * | ||
65 | * NOTE: MUST NOT be called from interrupt context, | ||
60 | * because the bus read/write functions may wait for an interrupt | 66 | * because the bus read/write functions may wait for an interrupt |
61 | * to conclude the operation. */ | 67 | * to conclude the operation. |
68 | */ | ||
62 | int phy_read(struct phy_device *phydev, u16 regnum) | 69 | int phy_read(struct phy_device *phydev, u16 regnum) |
63 | { | 70 | { |
64 | int retval; | 71 | int retval; |
@@ -72,6 +79,16 @@ int phy_read(struct phy_device *phydev, u16 regnum) | |||
72 | } | 79 | } |
73 | EXPORT_SYMBOL(phy_read); | 80 | EXPORT_SYMBOL(phy_read); |
74 | 81 | ||
82 | /** | ||
83 | * phy_write - Convenience function for writing a given PHY register | ||
84 | * @phydev: the phy_device struct | ||
85 | * @regnum: register number to write | ||
86 | * @val: value to write to @regnum | ||
87 | * | ||
88 | * NOTE: MUST NOT be called from interrupt context, | ||
89 | * because the bus read/write functions may wait for an interrupt | ||
90 | * to conclude the operation. | ||
91 | */ | ||
75 | int phy_write(struct phy_device *phydev, u16 regnum, u16 val) | 92 | int phy_write(struct phy_device *phydev, u16 regnum, u16 val) |
76 | { | 93 | { |
77 | int err; | 94 | int err; |
@@ -85,7 +102,15 @@ int phy_write(struct phy_device *phydev, u16 regnum, u16 val) | |||
85 | } | 102 | } |
86 | EXPORT_SYMBOL(phy_write); | 103 | EXPORT_SYMBOL(phy_write); |
87 | 104 | ||
88 | 105 | /** | |
106 | * phy_clear_interrupt - Ack the phy device's interrupt | ||
107 | * @phydev: the phy_device struct | ||
108 | * | ||
109 | * If the @phydev driver has an ack_interrupt function, call it to | ||
110 | * ack and clear the phy device's interrupt. | ||
111 | * | ||
112 | * Returns 0 on success on < 0 on error. | ||
113 | */ | ||
89 | int phy_clear_interrupt(struct phy_device *phydev) | 114 | int phy_clear_interrupt(struct phy_device *phydev) |
90 | { | 115 | { |
91 | int err = 0; | 116 | int err = 0; |
@@ -96,7 +121,13 @@ int phy_clear_interrupt(struct phy_device *phydev) | |||
96 | return err; | 121 | return err; |
97 | } | 122 | } |
98 | 123 | ||
99 | 124 | /** | |
125 | * phy_config_interrupt - configure the PHY device for the requested interrupts | ||
126 | * @phydev: the phy_device struct | ||
127 | * @interrupts: interrupt flags to configure for this @phydev | ||
128 | * | ||
129 | * Returns 0 on success on < 0 on error. | ||
130 | */ | ||
100 | int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) | 131 | int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) |
101 | { | 132 | { |
102 | int err = 0; | 133 | int err = 0; |
@@ -109,9 +140,11 @@ int phy_config_interrupt(struct phy_device *phydev, u32 interrupts) | |||
109 | } | 140 | } |
110 | 141 | ||
111 | 142 | ||
112 | /* phy_aneg_done | 143 | /** |
144 | * phy_aneg_done - return auto-negotiation status | ||
145 | * @phydev: target phy_device struct | ||
113 | * | 146 | * |
114 | * description: Reads the status register and returns 0 either if | 147 | * Description: Reads the status register and returns 0 either if |
115 | * auto-negotiation is incomplete, or if there was an error. | 148 | * auto-negotiation is incomplete, or if there was an error. |
116 | * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. | 149 | * Returns BMSR_ANEGCOMPLETE if auto-negotiation is done. |
117 | */ | 150 | */ |
@@ -173,9 +206,12 @@ static const struct phy_setting settings[] = { | |||
173 | 206 | ||
174 | #define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) | 207 | #define MAX_NUM_SETTINGS (sizeof(settings)/sizeof(struct phy_setting)) |
175 | 208 | ||
176 | /* phy_find_setting | 209 | /** |
210 | * phy_find_setting - find a PHY settings array entry that matches speed & duplex | ||
211 | * @speed: speed to match | ||
212 | * @duplex: duplex to match | ||
177 | * | 213 | * |
178 | * description: Searches the settings array for the setting which | 214 | * Description: Searches the settings array for the setting which |
179 | * matches the desired speed and duplex, and returns the index | 215 | * matches the desired speed and duplex, and returns the index |
180 | * of that setting. Returns the index of the last setting if | 216 | * of that setting. Returns the index of the last setting if |
181 | * none of the others match. | 217 | * none of the others match. |
@@ -192,11 +228,12 @@ static inline int phy_find_setting(int speed, int duplex) | |||
192 | return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; | 228 | return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; |
193 | } | 229 | } |
194 | 230 | ||
195 | /* phy_find_valid | 231 | /** |
196 | * idx: The first index in settings[] to search | 232 | * phy_find_valid - find a PHY setting that matches the requested features mask |
197 | * features: A mask of the valid settings | 233 | * @idx: The first index in settings[] to search |
234 | * @features: A mask of the valid settings | ||
198 | * | 235 | * |
199 | * description: Returns the index of the first valid setting less | 236 | * Description: Returns the index of the first valid setting less |
200 | * than or equal to the one pointed to by idx, as determined by | 237 | * than or equal to the one pointed to by idx, as determined by |
201 | * the mask in features. Returns the index of the last setting | 238 | * the mask in features. Returns the index of the last setting |
202 | * if nothing else matches. | 239 | * if nothing else matches. |
@@ -209,11 +246,13 @@ static inline int phy_find_valid(int idx, u32 features) | |||
209 | return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; | 246 | return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1; |
210 | } | 247 | } |
211 | 248 | ||
212 | /* phy_sanitize_settings | 249 | /** |
250 | * phy_sanitize_settings - make sure the PHY is set to supported speed and duplex | ||
251 | * @phydev: the target phy_device struct | ||
213 | * | 252 | * |
214 | * description: Make sure the PHY is set to supported speeds and | 253 | * Description: Make sure the PHY is set to supported speeds and |
215 | * duplexes. Drop down by one in this order: 1000/FULL, | 254 | * duplexes. Drop down by one in this order: 1000/FULL, |
216 | * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF | 255 | * 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF. |
217 | */ | 256 | */ |
218 | void phy_sanitize_settings(struct phy_device *phydev) | 257 | void phy_sanitize_settings(struct phy_device *phydev) |
219 | { | 258 | { |
@@ -232,16 +271,17 @@ void phy_sanitize_settings(struct phy_device *phydev) | |||
232 | } | 271 | } |
233 | EXPORT_SYMBOL(phy_sanitize_settings); | 272 | EXPORT_SYMBOL(phy_sanitize_settings); |
234 | 273 | ||
235 | /* phy_ethtool_sset: | 274 | /** |
236 | * A generic ethtool sset function. Handles all the details | 275 | * phy_ethtool_sset - generic ethtool sset function, handles all the details |
276 | * @phydev: target phy_device struct | ||
277 | * @cmd: ethtool_cmd | ||
237 | * | 278 | * |
238 | * A few notes about parameter checking: | 279 | * A few notes about parameter checking: |
239 | * - We don't set port or transceiver, so we don't care what they | 280 | * - We don't set port or transceiver, so we don't care what they |
240 | * were set to. | 281 | * were set to. |
241 | * - phy_start_aneg() will make sure forced settings are sane, and | 282 | * - phy_start_aneg() will make sure forced settings are sane, and |
242 | * choose the next best ones from the ones selected, so we don't | 283 | * choose the next best ones from the ones selected, so we don't |
243 | * care if ethtool tries to give us bad values | 284 | * care if ethtool tries to give us bad values. |
244 | * | ||
245 | */ | 285 | */ |
246 | int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) | 286 | int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) |
247 | { | 287 | { |
@@ -304,9 +344,15 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) | |||
304 | } | 344 | } |
305 | EXPORT_SYMBOL(phy_ethtool_gset); | 345 | EXPORT_SYMBOL(phy_ethtool_gset); |
306 | 346 | ||
307 | /* Note that this function is currently incompatible with the | 347 | /** |
348 | * phy_mii_ioctl - generic PHY MII ioctl interface | ||
349 | * @phydev: the phy_device struct | ||
350 | * @mii_data: MII ioctl data | ||
351 | * @cmd: ioctl cmd to execute | ||
352 | * | ||
353 | * Note that this function is currently incompatible with the | ||
308 | * PHYCONTROL layer. It changes registers without regard to | 354 | * PHYCONTROL layer. It changes registers without regard to |
309 | * current state. Use at own risk | 355 | * current state. Use at own risk. |
310 | */ | 356 | */ |
311 | int phy_mii_ioctl(struct phy_device *phydev, | 357 | int phy_mii_ioctl(struct phy_device *phydev, |
312 | struct mii_ioctl_data *mii_data, int cmd) | 358 | struct mii_ioctl_data *mii_data, int cmd) |
@@ -336,6 +382,12 @@ int phy_mii_ioctl(struct phy_device *phydev, | |||
336 | phydev->duplex = DUPLEX_FULL; | 382 | phydev->duplex = DUPLEX_FULL; |
337 | else | 383 | else |
338 | phydev->duplex = DUPLEX_HALF; | 384 | phydev->duplex = DUPLEX_HALF; |
385 | if ((!phydev->autoneg) && | ||
386 | (val & BMCR_SPEED1000)) | ||
387 | phydev->speed = SPEED_1000; | ||
388 | else if ((!phydev->autoneg) && | ||
389 | (val & BMCR_SPEED100)) | ||
390 | phydev->speed = SPEED_100; | ||
339 | break; | 391 | break; |
340 | case MII_ADVERTISE: | 392 | case MII_ADVERTISE: |
341 | phydev->advertising = val; | 393 | phydev->advertising = val; |
@@ -358,13 +410,14 @@ int phy_mii_ioctl(struct phy_device *phydev, | |||
358 | return 0; | 410 | return 0; |
359 | } | 411 | } |
360 | 412 | ||
361 | /* phy_start_aneg | 413 | /** |
414 | * phy_start_aneg - start auto-negotiation for this PHY device | ||
415 | * @phydev: the phy_device struct | ||
362 | * | 416 | * |
363 | * description: Sanitizes the settings (if we're not | 417 | * Description: Sanitizes the settings (if we're not autonegotiating |
364 | * autonegotiating them), and then calls the driver's | 418 | * them), and then calls the driver's config_aneg function. |
365 | * config_aneg function. If the PHYCONTROL Layer is operating, | 419 | * If the PHYCONTROL Layer is operating, we change the state to |
366 | * we change the state to reflect the beginning of | 420 | * reflect the beginning of Auto-negotiation or forcing. |
367 | * Auto-negotiation or forcing. | ||
368 | */ | 421 | */ |
369 | int phy_start_aneg(struct phy_device *phydev) | 422 | int phy_start_aneg(struct phy_device *phydev) |
370 | { | 423 | { |
@@ -400,15 +453,19 @@ EXPORT_SYMBOL(phy_start_aneg); | |||
400 | static void phy_change(struct work_struct *work); | 453 | static void phy_change(struct work_struct *work); |
401 | static void phy_timer(unsigned long data); | 454 | static void phy_timer(unsigned long data); |
402 | 455 | ||
403 | /* phy_start_machine: | 456 | /** |
457 | * phy_start_machine - start PHY state machine tracking | ||
458 | * @phydev: the phy_device struct | ||
459 | * @handler: callback function for state change notifications | ||
404 | * | 460 | * |
405 | * description: The PHY infrastructure can run a state machine | 461 | * Description: The PHY infrastructure can run a state machine |
406 | * which tracks whether the PHY is starting up, negotiating, | 462 | * which tracks whether the PHY is starting up, negotiating, |
407 | * etc. This function starts the timer which tracks the state | 463 | * etc. This function starts the timer which tracks the state |
408 | * of the PHY. If you want to be notified when the state | 464 | * of the PHY. If you want to be notified when the state changes, |
409 | * changes, pass in the callback, otherwise, pass NULL. If you | 465 | * pass in the callback @handler, otherwise, pass NULL. If you |
410 | * want to maintain your own state machine, do not call this | 466 | * want to maintain your own state machine, do not call this |
411 | * function. */ | 467 | * function. |
468 | */ | ||
412 | void phy_start_machine(struct phy_device *phydev, | 469 | void phy_start_machine(struct phy_device *phydev, |
413 | void (*handler)(struct net_device *)) | 470 | void (*handler)(struct net_device *)) |
414 | { | 471 | { |
@@ -420,9 +477,11 @@ void phy_start_machine(struct phy_device *phydev, | |||
420 | mod_timer(&phydev->phy_timer, jiffies + HZ); | 477 | mod_timer(&phydev->phy_timer, jiffies + HZ); |
421 | } | 478 | } |
422 | 479 | ||
423 | /* phy_stop_machine | 480 | /** |
481 | * phy_stop_machine - stop the PHY state machine tracking | ||
482 | * @phydev: target phy_device struct | ||
424 | * | 483 | * |
425 | * description: Stops the state machine timer, sets the state to UP | 484 | * Description: Stops the state machine timer, sets the state to UP |
426 | * (unless it wasn't up yet). This function must be called BEFORE | 485 | * (unless it wasn't up yet). This function must be called BEFORE |
427 | * phy_detach. | 486 | * phy_detach. |
428 | */ | 487 | */ |
@@ -438,12 +497,14 @@ void phy_stop_machine(struct phy_device *phydev) | |||
438 | phydev->adjust_state = NULL; | 497 | phydev->adjust_state = NULL; |
439 | } | 498 | } |
440 | 499 | ||
441 | /* phy_force_reduction | 500 | /** |
501 | * phy_force_reduction - reduce PHY speed/duplex settings by one step | ||
502 | * @phydev: target phy_device struct | ||
442 | * | 503 | * |
443 | * description: Reduces the speed/duplex settings by | 504 | * Description: Reduces the speed/duplex settings by one notch, |
444 | * one notch. The order is so: | 505 | * in this order-- |
445 | * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, | 506 | * 1000/FULL, 1000/HALF, 100/FULL, 100/HALF, 10/FULL, 10/HALF. |
446 | * 10/FULL, 10/HALF. The function bottoms out at 10/HALF. | 507 | * The function bottoms out at 10/HALF. |
447 | */ | 508 | */ |
448 | static void phy_force_reduction(struct phy_device *phydev) | 509 | static void phy_force_reduction(struct phy_device *phydev) |
449 | { | 510 | { |
@@ -464,7 +525,9 @@ static void phy_force_reduction(struct phy_device *phydev) | |||
464 | } | 525 | } |
465 | 526 | ||
466 | 527 | ||
467 | /* phy_error: | 528 | /** |
529 | * phy_error - enter HALTED state for this PHY device | ||
530 | * @phydev: target phy_device struct | ||
468 | * | 531 | * |
469 | * Moves the PHY to the HALTED state in response to a read | 532 | * Moves the PHY to the HALTED state in response to a read |
470 | * or write error, and tells the controller the link is down. | 533 | * or write error, and tells the controller the link is down. |
@@ -478,9 +541,12 @@ void phy_error(struct phy_device *phydev) | |||
478 | spin_unlock(&phydev->lock); | 541 | spin_unlock(&phydev->lock); |
479 | } | 542 | } |
480 | 543 | ||
481 | /* phy_interrupt | 544 | /** |
545 | * phy_interrupt - PHY interrupt handler | ||
546 | * @irq: interrupt line | ||
547 | * @phy_dat: phy_device pointer | ||
482 | * | 548 | * |
483 | * description: When a PHY interrupt occurs, the handler disables | 549 | * Description: When a PHY interrupt occurs, the handler disables |
484 | * interrupts, and schedules a work task to clear the interrupt. | 550 | * interrupts, and schedules a work task to clear the interrupt. |
485 | */ | 551 | */ |
486 | static irqreturn_t phy_interrupt(int irq, void *phy_dat) | 552 | static irqreturn_t phy_interrupt(int irq, void *phy_dat) |
@@ -501,7 +567,10 @@ static irqreturn_t phy_interrupt(int irq, void *phy_dat) | |||
501 | return IRQ_HANDLED; | 567 | return IRQ_HANDLED; |
502 | } | 568 | } |
503 | 569 | ||
504 | /* Enable the interrupts from the PHY side */ | 570 | /** |
571 | * phy_enable_interrupts - Enable the interrupts from the PHY side | ||
572 | * @phydev: target phy_device struct | ||
573 | */ | ||
505 | int phy_enable_interrupts(struct phy_device *phydev) | 574 | int phy_enable_interrupts(struct phy_device *phydev) |
506 | { | 575 | { |
507 | int err; | 576 | int err; |
@@ -517,7 +586,10 @@ int phy_enable_interrupts(struct phy_device *phydev) | |||
517 | } | 586 | } |
518 | EXPORT_SYMBOL(phy_enable_interrupts); | 587 | EXPORT_SYMBOL(phy_enable_interrupts); |
519 | 588 | ||
520 | /* Disable the PHY interrupts from the PHY side */ | 589 | /** |
590 | * phy_disable_interrupts - Disable the PHY interrupts from the PHY side | ||
591 | * @phydev: target phy_device struct | ||
592 | */ | ||
521 | int phy_disable_interrupts(struct phy_device *phydev) | 593 | int phy_disable_interrupts(struct phy_device *phydev) |
522 | { | 594 | { |
523 | int err; | 595 | int err; |
@@ -543,13 +615,15 @@ phy_err: | |||
543 | } | 615 | } |
544 | EXPORT_SYMBOL(phy_disable_interrupts); | 616 | EXPORT_SYMBOL(phy_disable_interrupts); |
545 | 617 | ||
546 | /* phy_start_interrupts | 618 | /** |
619 | * phy_start_interrupts - request and enable interrupts for a PHY device | ||
620 | * @phydev: target phy_device struct | ||
547 | * | 621 | * |
548 | * description: Request the interrupt for the given PHY. If | 622 | * Description: Request the interrupt for the given PHY. |
549 | * this fails, then we set irq to PHY_POLL. | 623 | * If this fails, then we set irq to PHY_POLL. |
550 | * Otherwise, we enable the interrupts in the PHY. | 624 | * Otherwise, we enable the interrupts in the PHY. |
551 | * Returns 0 on success. | ||
552 | * This should only be called with a valid IRQ number. | 625 | * This should only be called with a valid IRQ number. |
626 | * Returns 0 on success or < 0 on error. | ||
553 | */ | 627 | */ |
554 | int phy_start_interrupts(struct phy_device *phydev) | 628 | int phy_start_interrupts(struct phy_device *phydev) |
555 | { | 629 | { |
@@ -574,6 +648,10 @@ int phy_start_interrupts(struct phy_device *phydev) | |||
574 | } | 648 | } |
575 | EXPORT_SYMBOL(phy_start_interrupts); | 649 | EXPORT_SYMBOL(phy_start_interrupts); |
576 | 650 | ||
651 | /** | ||
652 | * phy_stop_interrupts - disable interrupts from a PHY device | ||
653 | * @phydev: target phy_device struct | ||
654 | */ | ||
577 | int phy_stop_interrupts(struct phy_device *phydev) | 655 | int phy_stop_interrupts(struct phy_device *phydev) |
578 | { | 656 | { |
579 | int err; | 657 | int err; |
@@ -596,7 +674,10 @@ int phy_stop_interrupts(struct phy_device *phydev) | |||
596 | EXPORT_SYMBOL(phy_stop_interrupts); | 674 | EXPORT_SYMBOL(phy_stop_interrupts); |
597 | 675 | ||
598 | 676 | ||
599 | /* Scheduled by the phy_interrupt/timer to handle PHY changes */ | 677 | /** |
678 | * phy_change - Scheduled by the phy_interrupt/timer to handle PHY changes | ||
679 | * @work: work_struct that describes the work to be done | ||
680 | */ | ||
600 | static void phy_change(struct work_struct *work) | 681 | static void phy_change(struct work_struct *work) |
601 | { | 682 | { |
602 | int err; | 683 | int err; |
@@ -630,7 +711,10 @@ phy_err: | |||
630 | phy_error(phydev); | 711 | phy_error(phydev); |
631 | } | 712 | } |
632 | 713 | ||
633 | /* Bring down the PHY link, and stop checking the status. */ | 714 | /** |
715 | * phy_stop - Bring down the PHY link, and stop checking the status | ||
716 | * @phydev: target phy_device struct | ||
717 | */ | ||
634 | void phy_stop(struct phy_device *phydev) | 718 | void phy_stop(struct phy_device *phydev) |
635 | { | 719 | { |
636 | spin_lock(&phydev->lock); | 720 | spin_lock(&phydev->lock); |
@@ -659,9 +743,11 @@ out_unlock: | |||
659 | } | 743 | } |
660 | 744 | ||
661 | 745 | ||
662 | /* phy_start | 746 | /** |
747 | * phy_start - start or restart a PHY device | ||
748 | * @phydev: target phy_device struct | ||
663 | * | 749 | * |
664 | * description: Indicates the attached device's readiness to | 750 | * Description: Indicates the attached device's readiness to |
665 | * handle PHY-related work. Used during startup to start the | 751 | * handle PHY-related work. Used during startup to start the |
666 | * PHY, and after a call to phy_stop() to resume operation. | 752 | * PHY, and after a call to phy_stop() to resume operation. |
667 | * Also used to indicate the MDIO bus has cleared an error | 753 | * Also used to indicate the MDIO bus has cleared an error |
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 8f01952c4850..a8b74cdab1ea 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -74,11 +74,13 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) | |||
74 | } | 74 | } |
75 | EXPORT_SYMBOL(phy_device_create); | 75 | EXPORT_SYMBOL(phy_device_create); |
76 | 76 | ||
77 | /* get_phy_device | 77 | /** |
78 | * get_phy_device - reads the specified PHY device and returns its @phy_device struct | ||
79 | * @bus: the target MII bus | ||
80 | * @addr: PHY address on the MII bus | ||
78 | * | 81 | * |
79 | * description: Reads the ID registers of the PHY at addr on the | 82 | * Description: Reads the ID registers of the PHY at @addr on the |
80 | * bus, then allocates and returns the phy_device to | 83 | * @bus, then allocates and returns the phy_device to represent it. |
81 | * represent it. | ||
82 | */ | 84 | */ |
83 | struct phy_device * get_phy_device(struct mii_bus *bus, int addr) | 85 | struct phy_device * get_phy_device(struct mii_bus *bus, int addr) |
84 | { | 86 | { |
@@ -112,23 +114,33 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) | |||
112 | return dev; | 114 | return dev; |
113 | } | 115 | } |
114 | 116 | ||
115 | /* phy_prepare_link: | 117 | /** |
118 | * phy_prepare_link - prepares the PHY layer to monitor link status | ||
119 | * @phydev: target phy_device struct | ||
120 | * @handler: callback function for link status change notifications | ||
116 | * | 121 | * |
117 | * description: Tells the PHY infrastructure to handle the | 122 | * Description: Tells the PHY infrastructure to handle the |
118 | * gory details on monitoring link status (whether through | 123 | * gory details on monitoring link status (whether through |
119 | * polling or an interrupt), and to call back to the | 124 | * polling or an interrupt), and to call back to the |
120 | * connected device driver when the link status changes. | 125 | * connected device driver when the link status changes. |
121 | * If you want to monitor your own link state, don't call | 126 | * If you want to monitor your own link state, don't call |
122 | * this function */ | 127 | * this function. |
128 | */ | ||
123 | void phy_prepare_link(struct phy_device *phydev, | 129 | void phy_prepare_link(struct phy_device *phydev, |
124 | void (*handler)(struct net_device *)) | 130 | void (*handler)(struct net_device *)) |
125 | { | 131 | { |
126 | phydev->adjust_link = handler; | 132 | phydev->adjust_link = handler; |
127 | } | 133 | } |
128 | 134 | ||
129 | /* phy_connect: | 135 | /** |
136 | * phy_connect - connect an ethernet device to a PHY device | ||
137 | * @dev: the network device to connect | ||
138 | * @phy_id: the PHY device to connect | ||
139 | * @handler: callback function for state change notifications | ||
140 | * @flags: PHY device's dev_flags | ||
141 | * @interface: PHY device's interface | ||
130 | * | 142 | * |
131 | * description: Convenience function for connecting ethernet | 143 | * Description: Convenience function for connecting ethernet |
132 | * devices to PHY devices. The default behavior is for | 144 | * devices to PHY devices. The default behavior is for |
133 | * the PHY infrastructure to handle everything, and only notify | 145 | * the PHY infrastructure to handle everything, and only notify |
134 | * the connected driver when the link status changes. If you | 146 | * the connected driver when the link status changes. If you |
@@ -158,6 +170,10 @@ struct phy_device * phy_connect(struct net_device *dev, const char *phy_id, | |||
158 | } | 170 | } |
159 | EXPORT_SYMBOL(phy_connect); | 171 | EXPORT_SYMBOL(phy_connect); |
160 | 172 | ||
173 | /** | ||
174 | * phy_disconnect - disable interrupts, stop state machine, and detach a PHY device | ||
175 | * @phydev: target phy_device struct | ||
176 | */ | ||
161 | void phy_disconnect(struct phy_device *phydev) | 177 | void phy_disconnect(struct phy_device *phydev) |
162 | { | 178 | { |
163 | if (phydev->irq > 0) | 179 | if (phydev->irq > 0) |
@@ -171,21 +187,25 @@ void phy_disconnect(struct phy_device *phydev) | |||
171 | } | 187 | } |
172 | EXPORT_SYMBOL(phy_disconnect); | 188 | EXPORT_SYMBOL(phy_disconnect); |
173 | 189 | ||
174 | /* phy_attach: | 190 | static int phy_compare_id(struct device *dev, void *data) |
191 | { | ||
192 | return strcmp((char *)data, dev->bus_id) ? 0 : 1; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * phy_attach - attach a network device to a particular PHY device | ||
197 | * @dev: network device to attach | ||
198 | * @phy_id: PHY device to attach | ||
199 | * @flags: PHY device's dev_flags | ||
200 | * @interface: PHY device's interface | ||
175 | * | 201 | * |
176 | * description: Called by drivers to attach to a particular PHY | 202 | * Description: Called by drivers to attach to a particular PHY |
177 | * device. The phy_device is found, and properly hooked up | 203 | * device. The phy_device is found, and properly hooked up |
178 | * to the phy_driver. If no driver is attached, then the | 204 | * to the phy_driver. If no driver is attached, then the |
179 | * genphy_driver is used. The phy_device is given a ptr to | 205 | * genphy_driver is used. The phy_device is given a ptr to |
180 | * the attaching device, and given a callback for link status | 206 | * the attaching device, and given a callback for link status |
181 | * change. The phy_device is returned to the attaching | 207 | * change. The phy_device is returned to the attaching driver. |
182 | * driver. | ||
183 | */ | 208 | */ |
184 | static int phy_compare_id(struct device *dev, void *data) | ||
185 | { | ||
186 | return strcmp((char *)data, dev->bus_id) ? 0 : 1; | ||
187 | } | ||
188 | |||
189 | struct phy_device *phy_attach(struct net_device *dev, | 209 | struct phy_device *phy_attach(struct net_device *dev, |
190 | const char *phy_id, u32 flags, phy_interface_t interface) | 210 | const char *phy_id, u32 flags, phy_interface_t interface) |
191 | { | 211 | { |
@@ -246,6 +266,10 @@ struct phy_device *phy_attach(struct net_device *dev, | |||
246 | } | 266 | } |
247 | EXPORT_SYMBOL(phy_attach); | 267 | EXPORT_SYMBOL(phy_attach); |
248 | 268 | ||
269 | /** | ||
270 | * phy_detach - detach a PHY device from its network device | ||
271 | * @phydev: target phy_device struct | ||
272 | */ | ||
249 | void phy_detach(struct phy_device *phydev) | 273 | void phy_detach(struct phy_device *phydev) |
250 | { | 274 | { |
251 | phydev->attached_dev = NULL; | 275 | phydev->attached_dev = NULL; |
@@ -262,11 +286,13 @@ EXPORT_SYMBOL(phy_detach); | |||
262 | 286 | ||
263 | /* Generic PHY support and helper functions */ | 287 | /* Generic PHY support and helper functions */ |
264 | 288 | ||
265 | /* genphy_config_advert | 289 | /** |
290 | * genphy_config_advert - sanitize and advertise auto-negotation parameters | ||
291 | * @phydev: target phy_device struct | ||
266 | * | 292 | * |
267 | * description: Writes MII_ADVERTISE with the appropriate values, | 293 | * Description: Writes MII_ADVERTISE with the appropriate values, |
268 | * after sanitizing the values to make sure we only advertise | 294 | * after sanitizing the values to make sure we only advertise |
269 | * what is supported | 295 | * what is supported. |
270 | */ | 296 | */ |
271 | int genphy_config_advert(struct phy_device *phydev) | 297 | int genphy_config_advert(struct phy_device *phydev) |
272 | { | 298 | { |
@@ -328,11 +354,14 @@ int genphy_config_advert(struct phy_device *phydev) | |||
328 | } | 354 | } |
329 | EXPORT_SYMBOL(genphy_config_advert); | 355 | EXPORT_SYMBOL(genphy_config_advert); |
330 | 356 | ||
331 | /* genphy_setup_forced | 357 | /** |
358 | * genphy_setup_forced - configures/forces speed/duplex from @phydev | ||
359 | * @phydev: target phy_device struct | ||
332 | * | 360 | * |
333 | * description: Configures MII_BMCR to force speed/duplex | 361 | * Description: Configures MII_BMCR to force speed/duplex |
334 | * to the values in phydev. Assumes that the values are valid. | 362 | * to the values in phydev. Assumes that the values are valid. |
335 | * Please see phy_sanitize_settings() */ | 363 | * Please see phy_sanitize_settings(). |
364 | */ | ||
336 | int genphy_setup_forced(struct phy_device *phydev) | 365 | int genphy_setup_forced(struct phy_device *phydev) |
337 | { | 366 | { |
338 | int ctl = BMCR_RESET; | 367 | int ctl = BMCR_RESET; |
@@ -361,7 +390,10 @@ int genphy_setup_forced(struct phy_device *phydev) | |||
361 | } | 390 | } |
362 | 391 | ||
363 | 392 | ||
364 | /* Enable and Restart Autonegotiation */ | 393 | /** |
394 | * genphy_restart_aneg - Enable and Restart Autonegotiation | ||
395 | * @phydev: target phy_device struct | ||
396 | */ | ||
365 | int genphy_restart_aneg(struct phy_device *phydev) | 397 | int genphy_restart_aneg(struct phy_device *phydev) |
366 | { | 398 | { |
367 | int ctl; | 399 | int ctl; |
@@ -382,11 +414,13 @@ int genphy_restart_aneg(struct phy_device *phydev) | |||
382 | } | 414 | } |
383 | 415 | ||
384 | 416 | ||
385 | /* genphy_config_aneg | 417 | /** |
418 | * genphy_config_aneg - restart auto-negotiation or write BMCR | ||
419 | * @phydev: target phy_device struct | ||
386 | * | 420 | * |
387 | * description: If auto-negotiation is enabled, we configure the | 421 | * Description: If auto-negotiation is enabled, we configure the |
388 | * advertising, and then restart auto-negotiation. If it is not | 422 | * advertising, and then restart auto-negotiation. If it is not |
389 | * enabled, then we write the BMCR | 423 | * enabled, then we write the BMCR. |
390 | */ | 424 | */ |
391 | int genphy_config_aneg(struct phy_device *phydev) | 425 | int genphy_config_aneg(struct phy_device *phydev) |
392 | { | 426 | { |
@@ -406,11 +440,13 @@ int genphy_config_aneg(struct phy_device *phydev) | |||
406 | } | 440 | } |
407 | EXPORT_SYMBOL(genphy_config_aneg); | 441 | EXPORT_SYMBOL(genphy_config_aneg); |
408 | 442 | ||
409 | /* genphy_update_link | 443 | /** |
444 | * genphy_update_link - update link status in @phydev | ||
445 | * @phydev: target phy_device struct | ||
410 | * | 446 | * |
411 | * description: Update the value in phydev->link to reflect the | 447 | * Description: Update the value in phydev->link to reflect the |
412 | * current link value. In order to do this, we need to read | 448 | * current link value. In order to do this, we need to read |
413 | * the status register twice, keeping the second value | 449 | * the status register twice, keeping the second value. |
414 | */ | 450 | */ |
415 | int genphy_update_link(struct phy_device *phydev) | 451 | int genphy_update_link(struct phy_device *phydev) |
416 | { | 452 | { |
@@ -437,9 +473,11 @@ int genphy_update_link(struct phy_device *phydev) | |||
437 | } | 473 | } |
438 | EXPORT_SYMBOL(genphy_update_link); | 474 | EXPORT_SYMBOL(genphy_update_link); |
439 | 475 | ||
440 | /* genphy_read_status | 476 | /** |
477 | * genphy_read_status - check the link status and update current link state | ||
478 | * @phydev: target phy_device struct | ||
441 | * | 479 | * |
442 | * description: Check the link, then figure out the current state | 480 | * Description: Check the link, then figure out the current state |
443 | * by comparing what we advertise with what the link partner | 481 | * by comparing what we advertise with what the link partner |
444 | * advertises. Start by checking the gigabit possibilities, | 482 | * advertises. Start by checking the gigabit possibilities, |
445 | * then move on to 10/100. | 483 | * then move on to 10/100. |
@@ -579,9 +617,11 @@ static int genphy_config_init(struct phy_device *phydev) | |||
579 | } | 617 | } |
580 | 618 | ||
581 | 619 | ||
582 | /* phy_probe | 620 | /** |
621 | * phy_probe - probe and init a PHY device | ||
622 | * @dev: device to probe and init | ||
583 | * | 623 | * |
584 | * description: Take care of setting up the phy_device structure, | 624 | * Description: Take care of setting up the phy_device structure, |
585 | * set the state to READY (the driver's init function should | 625 | * set the state to READY (the driver's init function should |
586 | * set it to STARTING if needed). | 626 | * set it to STARTING if needed). |
587 | */ | 627 | */ |
@@ -643,6 +683,10 @@ static int phy_remove(struct device *dev) | |||
643 | return 0; | 683 | return 0; |
644 | } | 684 | } |
645 | 685 | ||
686 | /** | ||
687 | * phy_driver_register - register a phy_driver with the PHY layer | ||
688 | * @new_driver: new phy_driver to register | ||
689 | */ | ||
646 | int phy_driver_register(struct phy_driver *new_driver) | 690 | int phy_driver_register(struct phy_driver *new_driver) |
647 | { | 691 | { |
648 | int retval; | 692 | int retval; |
diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 7b80fb7a9d9b..d8766c0e8255 100755 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c | |||
@@ -39,7 +39,7 @@ | |||
39 | 39 | ||
40 | #define DRV_NAME "qla3xxx" | 40 | #define DRV_NAME "qla3xxx" |
41 | #define DRV_STRING "QLogic ISP3XXX Network Driver" | 41 | #define DRV_STRING "QLogic ISP3XXX Network Driver" |
42 | #define DRV_VERSION "v2.03.00-k3" | 42 | #define DRV_VERSION "v2.03.00-k4" |
43 | #define PFX DRV_NAME " " | 43 | #define PFX DRV_NAME " " |
44 | 44 | ||
45 | static const char ql3xxx_driver_name[] = DRV_NAME; | 45 | static const char ql3xxx_driver_name[] = DRV_NAME; |
@@ -72,6 +72,30 @@ static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = { | |||
72 | MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl); | 72 | MODULE_DEVICE_TABLE(pci, ql3xxx_pci_tbl); |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * These are the known PHY's which are used | ||
76 | */ | ||
77 | typedef enum { | ||
78 | PHY_TYPE_UNKNOWN = 0, | ||
79 | PHY_VITESSE_VSC8211, | ||
80 | PHY_AGERE_ET1011C, | ||
81 | MAX_PHY_DEV_TYPES | ||
82 | } PHY_DEVICE_et; | ||
83 | |||
84 | typedef struct { | ||
85 | PHY_DEVICE_et phyDevice; | ||
86 | u32 phyIdOUI; | ||
87 | u16 phyIdModel; | ||
88 | char *name; | ||
89 | } PHY_DEVICE_INFO_t; | ||
90 | |||
91 | static const PHY_DEVICE_INFO_t PHY_DEVICES[] = | ||
92 | {{PHY_TYPE_UNKNOWN, 0x000000, 0x0, "PHY_TYPE_UNKNOWN"}, | ||
93 | {PHY_VITESSE_VSC8211, 0x0003f1, 0xb, "PHY_VITESSE_VSC8211"}, | ||
94 | {PHY_AGERE_ET1011C, 0x00a0bc, 0x1, "PHY_AGERE_ET1011C"}, | ||
95 | }; | ||
96 | |||
97 | |||
98 | /* | ||
75 | * Caller must take hw_lock. | 99 | * Caller must take hw_lock. |
76 | */ | 100 | */ |
77 | static int ql_sem_spinlock(struct ql3_adapter *qdev, | 101 | static int ql_sem_spinlock(struct ql3_adapter *qdev, |
@@ -662,7 +686,7 @@ static u8 ql_mii_disable_scan_mode(struct ql3_adapter *qdev) | |||
662 | } | 686 | } |
663 | 687 | ||
664 | static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, | 688 | static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, |
665 | u16 regAddr, u16 value, u32 mac_index) | 689 | u16 regAddr, u16 value, u32 phyAddr) |
666 | { | 690 | { |
667 | struct ql3xxx_port_registers __iomem *port_regs = | 691 | struct ql3xxx_port_registers __iomem *port_regs = |
668 | qdev->mem_map_registers; | 692 | qdev->mem_map_registers; |
@@ -680,7 +704,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, | |||
680 | } | 704 | } |
681 | 705 | ||
682 | ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, | 706 | ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, |
683 | PHYAddr[mac_index] | regAddr); | 707 | phyAddr | regAddr); |
684 | 708 | ||
685 | ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value); | 709 | ql_write_page0_reg(qdev, &port_regs->macMIIMgmtDataReg, value); |
686 | 710 | ||
@@ -701,7 +725,7 @@ static int ql_mii_write_reg_ex(struct ql3_adapter *qdev, | |||
701 | } | 725 | } |
702 | 726 | ||
703 | static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr, | 727 | static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr, |
704 | u16 * value, u32 mac_index) | 728 | u16 * value, u32 phyAddr) |
705 | { | 729 | { |
706 | struct ql3xxx_port_registers __iomem *port_regs = | 730 | struct ql3xxx_port_registers __iomem *port_regs = |
707 | qdev->mem_map_registers; | 731 | qdev->mem_map_registers; |
@@ -720,7 +744,7 @@ static int ql_mii_read_reg_ex(struct ql3_adapter *qdev, u16 regAddr, | |||
720 | } | 744 | } |
721 | 745 | ||
722 | ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, | 746 | ql_write_page0_reg(qdev, &port_regs->macMIIMgmtAddrReg, |
723 | PHYAddr[mac_index] | regAddr); | 747 | phyAddr | regAddr); |
724 | 748 | ||
725 | ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, | 749 | ql_write_page0_reg(qdev, &port_regs->macMIIMgmtControlReg, |
726 | (MAC_MII_CONTROL_RC << 16)); | 750 | (MAC_MII_CONTROL_RC << 16)); |
@@ -850,28 +874,31 @@ static void ql_petbi_start_neg(struct ql3_adapter *qdev) | |||
850 | 874 | ||
851 | } | 875 | } |
852 | 876 | ||
853 | static void ql_petbi_reset_ex(struct ql3_adapter *qdev, u32 mac_index) | 877 | static void ql_petbi_reset_ex(struct ql3_adapter *qdev) |
854 | { | 878 | { |
855 | ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET, | 879 | ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, PETBI_CTRL_SOFT_RESET, |
856 | mac_index); | 880 | PHYAddr[qdev->mac_index]); |
857 | } | 881 | } |
858 | 882 | ||
859 | static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index) | 883 | static void ql_petbi_start_neg_ex(struct ql3_adapter *qdev) |
860 | { | 884 | { |
861 | u16 reg; | 885 | u16 reg; |
862 | 886 | ||
863 | /* Enable Auto-negotiation sense */ | 887 | /* Enable Auto-negotiation sense */ |
864 | ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, mac_index); | 888 | ql_mii_read_reg_ex(qdev, PETBI_TBI_CTRL, ®, |
889 | PHYAddr[qdev->mac_index]); | ||
865 | reg |= PETBI_TBI_AUTO_SENSE; | 890 | reg |= PETBI_TBI_AUTO_SENSE; |
866 | ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, mac_index); | 891 | ql_mii_write_reg_ex(qdev, PETBI_TBI_CTRL, reg, |
892 | PHYAddr[qdev->mac_index]); | ||
867 | 893 | ||
868 | ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER, | 894 | ql_mii_write_reg_ex(qdev, PETBI_NEG_ADVER, |
869 | PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, mac_index); | 895 | PETBI_NEG_PAUSE | PETBI_NEG_DUPLEX, |
896 | PHYAddr[qdev->mac_index]); | ||
870 | 897 | ||
871 | ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, | 898 | ql_mii_write_reg_ex(qdev, PETBI_CONTROL_REG, |
872 | PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG | | 899 | PETBI_CTRL_AUTO_NEG | PETBI_CTRL_RESTART_NEG | |
873 | PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000, | 900 | PETBI_CTRL_FULL_DUPLEX | PETBI_CTRL_SPEED_1000, |
874 | mac_index); | 901 | PHYAddr[qdev->mac_index]); |
875 | } | 902 | } |
876 | 903 | ||
877 | static void ql_petbi_init(struct ql3_adapter *qdev) | 904 | static void ql_petbi_init(struct ql3_adapter *qdev) |
@@ -880,10 +907,10 @@ static void ql_petbi_init(struct ql3_adapter *qdev) | |||
880 | ql_petbi_start_neg(qdev); | 907 | ql_petbi_start_neg(qdev); |
881 | } | 908 | } |
882 | 909 | ||
883 | static void ql_petbi_init_ex(struct ql3_adapter *qdev, u32 mac_index) | 910 | static void ql_petbi_init_ex(struct ql3_adapter *qdev) |
884 | { | 911 | { |
885 | ql_petbi_reset_ex(qdev, mac_index); | 912 | ql_petbi_reset_ex(qdev); |
886 | ql_petbi_start_neg_ex(qdev, mac_index); | 913 | ql_petbi_start_neg_ex(qdev); |
887 | } | 914 | } |
888 | 915 | ||
889 | static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev) | 916 | static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev) |
@@ -896,33 +923,128 @@ static int ql_is_petbi_neg_pause(struct ql3_adapter *qdev) | |||
896 | return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE; | 923 | return (reg & PETBI_NEG_PAUSE_MASK) == PETBI_NEG_PAUSE; |
897 | } | 924 | } |
898 | 925 | ||
926 | static void phyAgereSpecificInit(struct ql3_adapter *qdev, u32 miiAddr) | ||
927 | { | ||
928 | printk(KERN_INFO "%s: enabling Agere specific PHY\n", qdev->ndev->name); | ||
929 | /* power down device bit 11 = 1 */ | ||
930 | ql_mii_write_reg_ex(qdev, 0x00, 0x1940, miiAddr); | ||
931 | /* enable diagnostic mode bit 2 = 1 */ | ||
932 | ql_mii_write_reg_ex(qdev, 0x12, 0x840e, miiAddr); | ||
933 | /* 1000MB amplitude adjust (see Agere errata) */ | ||
934 | ql_mii_write_reg_ex(qdev, 0x10, 0x8805, miiAddr); | ||
935 | /* 1000MB amplitude adjust (see Agere errata) */ | ||
936 | ql_mii_write_reg_ex(qdev, 0x11, 0xf03e, miiAddr); | ||
937 | /* 100MB amplitude adjust (see Agere errata) */ | ||
938 | ql_mii_write_reg_ex(qdev, 0x10, 0x8806, miiAddr); | ||
939 | /* 100MB amplitude adjust (see Agere errata) */ | ||
940 | ql_mii_write_reg_ex(qdev, 0x11, 0x003e, miiAddr); | ||
941 | /* 10MB amplitude adjust (see Agere errata) */ | ||
942 | ql_mii_write_reg_ex(qdev, 0x10, 0x8807, miiAddr); | ||
943 | /* 10MB amplitude adjust (see Agere errata) */ | ||
944 | ql_mii_write_reg_ex(qdev, 0x11, 0x1f00, miiAddr); | ||
945 | /* point to hidden reg 0x2806 */ | ||
946 | ql_mii_write_reg_ex(qdev, 0x10, 0x2806, miiAddr); | ||
947 | /* Write new PHYAD w/bit 5 set */ | ||
948 | ql_mii_write_reg_ex(qdev, 0x11, 0x0020 | (PHYAddr[qdev->mac_index] >> 8), miiAddr); | ||
949 | /* | ||
950 | * Disable diagnostic mode bit 2 = 0 | ||
951 | * Power up device bit 11 = 0 | ||
952 | * Link up (on) and activity (blink) | ||
953 | */ | ||
954 | ql_mii_write_reg(qdev, 0x12, 0x840a); | ||
955 | ql_mii_write_reg(qdev, 0x00, 0x1140); | ||
956 | ql_mii_write_reg(qdev, 0x1c, 0xfaf0); | ||
957 | } | ||
958 | |||
959 | static PHY_DEVICE_et getPhyType (struct ql3_adapter *qdev, | ||
960 | u16 phyIdReg0, u16 phyIdReg1) | ||
961 | { | ||
962 | PHY_DEVICE_et result = PHY_TYPE_UNKNOWN; | ||
963 | u32 oui; | ||
964 | u16 model; | ||
965 | int i; | ||
966 | |||
967 | if (phyIdReg0 == 0xffff) { | ||
968 | return result; | ||
969 | } | ||
970 | |||
971 | if (phyIdReg1 == 0xffff) { | ||
972 | return result; | ||
973 | } | ||
974 | |||
975 | /* oui is split between two registers */ | ||
976 | oui = (phyIdReg0 << 6) | ((phyIdReg1 & PHY_OUI_1_MASK) >> 10); | ||
977 | |||
978 | model = (phyIdReg1 & PHY_MODEL_MASK) >> 4; | ||
979 | |||
980 | /* Scan table for this PHY */ | ||
981 | for(i = 0; i < MAX_PHY_DEV_TYPES; i++) { | ||
982 | if ((oui == PHY_DEVICES[i].phyIdOUI) && (model == PHY_DEVICES[i].phyIdModel)) | ||
983 | { | ||
984 | result = PHY_DEVICES[i].phyDevice; | ||
985 | |||
986 | printk(KERN_INFO "%s: Phy: %s\n", | ||
987 | qdev->ndev->name, PHY_DEVICES[i].name); | ||
988 | |||
989 | break; | ||
990 | } | ||
991 | } | ||
992 | |||
993 | return result; | ||
994 | } | ||
995 | |||
899 | static int ql_phy_get_speed(struct ql3_adapter *qdev) | 996 | static int ql_phy_get_speed(struct ql3_adapter *qdev) |
900 | { | 997 | { |
901 | u16 reg; | 998 | u16 reg; |
902 | 999 | ||
1000 | switch(qdev->phyType) { | ||
1001 | case PHY_AGERE_ET1011C: | ||
1002 | { | ||
1003 | if (ql_mii_read_reg(qdev, 0x1A, ®) < 0) | ||
1004 | return 0; | ||
1005 | |||
1006 | reg = (reg >> 8) & 3; | ||
1007 | break; | ||
1008 | } | ||
1009 | default: | ||
903 | if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) | 1010 | if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) |
904 | return 0; | 1011 | return 0; |
905 | 1012 | ||
906 | reg = (((reg & 0x18) >> 3) & 3); | 1013 | reg = (((reg & 0x18) >> 3) & 3); |
1014 | } | ||
907 | 1015 | ||
908 | if (reg == 2) | 1016 | switch(reg) { |
1017 | case 2: | ||
909 | return SPEED_1000; | 1018 | return SPEED_1000; |
910 | else if (reg == 1) | 1019 | case 1: |
911 | return SPEED_100; | 1020 | return SPEED_100; |
912 | else if (reg == 0) | 1021 | case 0: |
913 | return SPEED_10; | 1022 | return SPEED_10; |
914 | else | 1023 | default: |
915 | return -1; | 1024 | return -1; |
1025 | } | ||
916 | } | 1026 | } |
917 | 1027 | ||
918 | static int ql_is_full_dup(struct ql3_adapter *qdev) | 1028 | static int ql_is_full_dup(struct ql3_adapter *qdev) |
919 | { | 1029 | { |
920 | u16 reg; | 1030 | u16 reg; |
921 | 1031 | ||
922 | if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) | 1032 | switch(qdev->phyType) { |
923 | return 0; | 1033 | case PHY_AGERE_ET1011C: |
924 | 1034 | { | |
925 | return (reg & PHY_AUX_DUPLEX_STAT) != 0; | 1035 | if (ql_mii_read_reg(qdev, 0x1A, ®)) |
1036 | return 0; | ||
1037 | |||
1038 | return ((reg & 0x0080) && (reg & 0x1000)) != 0; | ||
1039 | } | ||
1040 | case PHY_VITESSE_VSC8211: | ||
1041 | default: | ||
1042 | { | ||
1043 | if (ql_mii_read_reg(qdev, AUX_CONTROL_STATUS, ®) < 0) | ||
1044 | return 0; | ||
1045 | return (reg & PHY_AUX_DUPLEX_STAT) != 0; | ||
1046 | } | ||
1047 | } | ||
926 | } | 1048 | } |
927 | 1049 | ||
928 | static int ql_is_phy_neg_pause(struct ql3_adapter *qdev) | 1050 | static int ql_is_phy_neg_pause(struct ql3_adapter *qdev) |
@@ -935,6 +1057,73 @@ static int ql_is_phy_neg_pause(struct ql3_adapter *qdev) | |||
935 | return (reg & PHY_NEG_PAUSE) != 0; | 1057 | return (reg & PHY_NEG_PAUSE) != 0; |
936 | } | 1058 | } |
937 | 1059 | ||
1060 | static int PHY_Setup(struct ql3_adapter *qdev) | ||
1061 | { | ||
1062 | u16 reg1; | ||
1063 | u16 reg2; | ||
1064 | bool agereAddrChangeNeeded = false; | ||
1065 | u32 miiAddr = 0; | ||
1066 | int err; | ||
1067 | |||
1068 | /* Determine the PHY we are using by reading the ID's */ | ||
1069 | err = ql_mii_read_reg(qdev, PHY_ID_0_REG, ®1); | ||
1070 | if(err != 0) { | ||
1071 | printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n", | ||
1072 | qdev->ndev->name); | ||
1073 | return err; | ||
1074 | } | ||
1075 | |||
1076 | err = ql_mii_read_reg(qdev, PHY_ID_1_REG, ®2); | ||
1077 | if(err != 0) { | ||
1078 | printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG\n", | ||
1079 | qdev->ndev->name); | ||
1080 | return err; | ||
1081 | } | ||
1082 | |||
1083 | /* Check if we have a Agere PHY */ | ||
1084 | if ((reg1 == 0xffff) || (reg2 == 0xffff)) { | ||
1085 | |||
1086 | /* Determine which MII address we should be using | ||
1087 | determined by the index of the card */ | ||
1088 | if (qdev->mac_index == 0) { | ||
1089 | miiAddr = MII_AGERE_ADDR_1; | ||
1090 | } else { | ||
1091 | miiAddr = MII_AGERE_ADDR_2; | ||
1092 | } | ||
1093 | |||
1094 | err =ql_mii_read_reg_ex(qdev, PHY_ID_0_REG, ®1, miiAddr); | ||
1095 | if(err != 0) { | ||
1096 | printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n", | ||
1097 | qdev->ndev->name); | ||
1098 | return err; | ||
1099 | } | ||
1100 | |||
1101 | err = ql_mii_read_reg_ex(qdev, PHY_ID_1_REG, ®2, miiAddr); | ||
1102 | if(err != 0) { | ||
1103 | printk(KERN_ERR "%s: Could not read from reg PHY_ID_0_REG after Agere detected\n", | ||
1104 | qdev->ndev->name); | ||
1105 | return err; | ||
1106 | } | ||
1107 | |||
1108 | /* We need to remember to initialize the Agere PHY */ | ||
1109 | agereAddrChangeNeeded = true; | ||
1110 | } | ||
1111 | |||
1112 | /* Determine the particular PHY we have on board to apply | ||
1113 | PHY specific initializations */ | ||
1114 | qdev->phyType = getPhyType(qdev, reg1, reg2); | ||
1115 | |||
1116 | if ((qdev->phyType == PHY_AGERE_ET1011C) && agereAddrChangeNeeded) { | ||
1117 | /* need this here so address gets changed */ | ||
1118 | phyAgereSpecificInit(qdev, miiAddr); | ||
1119 | } else if (qdev->phyType == PHY_TYPE_UNKNOWN) { | ||
1120 | printk(KERN_ERR "%s: PHY is unknown\n", qdev->ndev->name); | ||
1121 | return -EIO; | ||
1122 | } | ||
1123 | |||
1124 | return 0; | ||
1125 | } | ||
1126 | |||
938 | /* | 1127 | /* |
939 | * Caller holds hw_lock. | 1128 | * Caller holds hw_lock. |
940 | */ | 1129 | */ |
@@ -1205,15 +1394,14 @@ static int ql_link_down_detect_clear(struct ql3_adapter *qdev) | |||
1205 | /* | 1394 | /* |
1206 | * Caller holds hw_lock. | 1395 | * Caller holds hw_lock. |
1207 | */ | 1396 | */ |
1208 | static int ql_this_adapter_controls_port(struct ql3_adapter *qdev, | 1397 | static int ql_this_adapter_controls_port(struct ql3_adapter *qdev) |
1209 | u32 mac_index) | ||
1210 | { | 1398 | { |
1211 | struct ql3xxx_port_registers __iomem *port_regs = | 1399 | struct ql3xxx_port_registers __iomem *port_regs = |
1212 | qdev->mem_map_registers; | 1400 | qdev->mem_map_registers; |
1213 | u32 bitToCheck = 0; | 1401 | u32 bitToCheck = 0; |
1214 | u32 temp; | 1402 | u32 temp; |
1215 | 1403 | ||
1216 | switch (mac_index) { | 1404 | switch (qdev->mac_index) { |
1217 | case 0: | 1405 | case 0: |
1218 | bitToCheck = PORT_STATUS_F1_ENABLED; | 1406 | bitToCheck = PORT_STATUS_F1_ENABLED; |
1219 | break; | 1407 | break; |
@@ -1238,27 +1426,96 @@ static int ql_this_adapter_controls_port(struct ql3_adapter *qdev, | |||
1238 | } | 1426 | } |
1239 | } | 1427 | } |
1240 | 1428 | ||
1241 | static void ql_phy_reset_ex(struct ql3_adapter *qdev, u32 mac_index) | 1429 | static void ql_phy_reset_ex(struct ql3_adapter *qdev) |
1242 | { | 1430 | { |
1243 | ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, mac_index); | 1431 | ql_mii_write_reg_ex(qdev, CONTROL_REG, PHY_CTRL_SOFT_RESET, |
1432 | PHYAddr[qdev->mac_index]); | ||
1244 | } | 1433 | } |
1245 | 1434 | ||
1246 | static void ql_phy_start_neg_ex(struct ql3_adapter *qdev, u32 mac_index) | 1435 | static void ql_phy_start_neg_ex(struct ql3_adapter *qdev) |
1247 | { | 1436 | { |
1248 | u16 reg; | 1437 | u16 reg; |
1438 | u16 portConfiguration; | ||
1439 | |||
1440 | if(qdev->phyType == PHY_AGERE_ET1011C) { | ||
1441 | /* turn off external loopback */ | ||
1442 | ql_mii_write_reg(qdev, 0x13, 0x0000); | ||
1443 | } | ||
1444 | |||
1445 | if(qdev->mac_index == 0) | ||
1446 | portConfiguration = qdev->nvram_data.macCfg_port0.portConfiguration; | ||
1447 | else | ||
1448 | portConfiguration = qdev->nvram_data.macCfg_port1.portConfiguration; | ||
1449 | |||
1450 | /* Some HBA's in the field are set to 0 and they need to | ||
1451 | be reinterpreted with a default value */ | ||
1452 | if(portConfiguration == 0) | ||
1453 | portConfiguration = PORT_CONFIG_DEFAULT; | ||
1454 | |||
1455 | /* Set the 1000 advertisements */ | ||
1456 | ql_mii_read_reg_ex(qdev, PHY_GIG_CONTROL, ®, | ||
1457 | PHYAddr[qdev->mac_index]); | ||
1458 | reg &= ~PHY_GIG_ALL_PARAMS; | ||
1459 | |||
1460 | if(portConfiguration & | ||
1461 | PORT_CONFIG_FULL_DUPLEX_ENABLED & | ||
1462 | PORT_CONFIG_1000MB_SPEED) { | ||
1463 | reg |= PHY_GIG_ADV_1000F; | ||
1464 | } | ||
1465 | |||
1466 | if(portConfiguration & | ||
1467 | PORT_CONFIG_HALF_DUPLEX_ENABLED & | ||
1468 | PORT_CONFIG_1000MB_SPEED) { | ||
1469 | reg |= PHY_GIG_ADV_1000H; | ||
1470 | } | ||
1249 | 1471 | ||
1250 | ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, | 1472 | ql_mii_write_reg_ex(qdev, PHY_GIG_CONTROL, reg, |
1251 | PHY_NEG_PAUSE | PHY_NEG_ADV_SPEED | 1, mac_index); | 1473 | PHYAddr[qdev->mac_index]); |
1252 | 1474 | ||
1253 | ql_mii_read_reg_ex(qdev, CONTROL_REG, ®, mac_index); | 1475 | /* Set the 10/100 & pause negotiation advertisements */ |
1254 | ql_mii_write_reg_ex(qdev, CONTROL_REG, reg | PHY_CTRL_RESTART_NEG, | 1476 | ql_mii_read_reg_ex(qdev, PHY_NEG_ADVER, ®, |
1255 | mac_index); | 1477 | PHYAddr[qdev->mac_index]); |
1478 | reg &= ~PHY_NEG_ALL_PARAMS; | ||
1479 | |||
1480 | if(portConfiguration & PORT_CONFIG_SYM_PAUSE_ENABLED) | ||
1481 | reg |= PHY_NEG_ASY_PAUSE | PHY_NEG_SYM_PAUSE; | ||
1482 | |||
1483 | if(portConfiguration & PORT_CONFIG_FULL_DUPLEX_ENABLED) { | ||
1484 | if(portConfiguration & PORT_CONFIG_100MB_SPEED) | ||
1485 | reg |= PHY_NEG_ADV_100F; | ||
1486 | |||
1487 | if(portConfiguration & PORT_CONFIG_10MB_SPEED) | ||
1488 | reg |= PHY_NEG_ADV_10F; | ||
1489 | } | ||
1490 | |||
1491 | if(portConfiguration & PORT_CONFIG_HALF_DUPLEX_ENABLED) { | ||
1492 | if(portConfiguration & PORT_CONFIG_100MB_SPEED) | ||
1493 | reg |= PHY_NEG_ADV_100H; | ||
1494 | |||
1495 | if(portConfiguration & PORT_CONFIG_10MB_SPEED) | ||
1496 | reg |= PHY_NEG_ADV_10H; | ||
1497 | } | ||
1498 | |||
1499 | if(portConfiguration & | ||
1500 | PORT_CONFIG_1000MB_SPEED) { | ||
1501 | reg |= 1; | ||
1502 | } | ||
1503 | |||
1504 | ql_mii_write_reg_ex(qdev, PHY_NEG_ADVER, reg, | ||
1505 | PHYAddr[qdev->mac_index]); | ||
1506 | |||
1507 | ql_mii_read_reg_ex(qdev, CONTROL_REG, ®, PHYAddr[qdev->mac_index]); | ||
1508 | |||
1509 | ql_mii_write_reg_ex(qdev, CONTROL_REG, | ||
1510 | reg | PHY_CTRL_RESTART_NEG | PHY_CTRL_AUTO_NEG, | ||
1511 | PHYAddr[qdev->mac_index]); | ||
1256 | } | 1512 | } |
1257 | 1513 | ||
1258 | static void ql_phy_init_ex(struct ql3_adapter *qdev, u32 mac_index) | 1514 | static void ql_phy_init_ex(struct ql3_adapter *qdev) |
1259 | { | 1515 | { |
1260 | ql_phy_reset_ex(qdev, mac_index); | 1516 | ql_phy_reset_ex(qdev); |
1261 | ql_phy_start_neg_ex(qdev, mac_index); | 1517 | PHY_Setup(qdev); |
1518 | ql_phy_start_neg_ex(qdev); | ||
1262 | } | 1519 | } |
1263 | 1520 | ||
1264 | /* | 1521 | /* |
@@ -1295,14 +1552,17 @@ static int ql_port_start(struct ql3_adapter *qdev) | |||
1295 | { | 1552 | { |
1296 | if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, | 1553 | if(ql_sem_spinlock(qdev, QL_PHY_GIO_SEM_MASK, |
1297 | (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * | 1554 | (QL_RESOURCE_BITS_BASE_CODE | (qdev->mac_index) * |
1298 | 2) << 7)) | 1555 | 2) << 7)) { |
1556 | printk(KERN_ERR "%s: Could not get hw lock for GIO\n", | ||
1557 | qdev->ndev->name); | ||
1299 | return -1; | 1558 | return -1; |
1559 | } | ||
1300 | 1560 | ||
1301 | if (ql_is_fiber(qdev)) { | 1561 | if (ql_is_fiber(qdev)) { |
1302 | ql_petbi_init(qdev); | 1562 | ql_petbi_init(qdev); |
1303 | } else { | 1563 | } else { |
1304 | /* Copper port */ | 1564 | /* Copper port */ |
1305 | ql_phy_init_ex(qdev, qdev->mac_index); | 1565 | ql_phy_init_ex(qdev); |
1306 | } | 1566 | } |
1307 | 1567 | ||
1308 | ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); | 1568 | ql_sem_unlock(qdev, QL_PHY_GIO_SEM_MASK); |
@@ -1453,7 +1713,7 @@ static void ql_link_state_machine(struct ql3_adapter *qdev) | |||
1453 | */ | 1713 | */ |
1454 | static void ql_get_phy_owner(struct ql3_adapter *qdev) | 1714 | static void ql_get_phy_owner(struct ql3_adapter *qdev) |
1455 | { | 1715 | { |
1456 | if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) | 1716 | if (ql_this_adapter_controls_port(qdev)) |
1457 | set_bit(QL_LINK_MASTER,&qdev->flags); | 1717 | set_bit(QL_LINK_MASTER,&qdev->flags); |
1458 | else | 1718 | else |
1459 | clear_bit(QL_LINK_MASTER,&qdev->flags); | 1719 | clear_bit(QL_LINK_MASTER,&qdev->flags); |
@@ -1467,11 +1727,11 @@ static void ql_init_scan_mode(struct ql3_adapter *qdev) | |||
1467 | ql_mii_enable_scan_mode(qdev); | 1727 | ql_mii_enable_scan_mode(qdev); |
1468 | 1728 | ||
1469 | if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) { | 1729 | if (test_bit(QL_LINK_OPTICAL,&qdev->flags)) { |
1470 | if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) | 1730 | if (ql_this_adapter_controls_port(qdev)) |
1471 | ql_petbi_init_ex(qdev, qdev->mac_index); | 1731 | ql_petbi_init_ex(qdev); |
1472 | } else { | 1732 | } else { |
1473 | if (ql_this_adapter_controls_port(qdev, qdev->mac_index)) | 1733 | if (ql_this_adapter_controls_port(qdev)) |
1474 | ql_phy_init_ex(qdev, qdev->mac_index); | 1734 | ql_phy_init_ex(qdev); |
1475 | } | 1735 | } |
1476 | } | 1736 | } |
1477 | 1737 | ||
@@ -1624,6 +1884,23 @@ static void ql_set_msglevel(struct net_device *ndev, u32 value) | |||
1624 | qdev->msg_enable = value; | 1884 | qdev->msg_enable = value; |
1625 | } | 1885 | } |
1626 | 1886 | ||
1887 | static void ql_get_pauseparam(struct net_device *ndev, | ||
1888 | struct ethtool_pauseparam *pause) | ||
1889 | { | ||
1890 | struct ql3_adapter *qdev = netdev_priv(ndev); | ||
1891 | struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; | ||
1892 | |||
1893 | u32 reg; | ||
1894 | if(qdev->mac_index == 0) | ||
1895 | reg = ql_read_page0_reg(qdev, &port_regs->mac0ConfigReg); | ||
1896 | else | ||
1897 | reg = ql_read_page0_reg(qdev, &port_regs->mac1ConfigReg); | ||
1898 | |||
1899 | pause->autoneg = ql_get_auto_cfg_status(qdev); | ||
1900 | pause->rx_pause = (reg & MAC_CONFIG_REG_RF) >> 2; | ||
1901 | pause->tx_pause = (reg & MAC_CONFIG_REG_TF) >> 1; | ||
1902 | } | ||
1903 | |||
1627 | static const struct ethtool_ops ql3xxx_ethtool_ops = { | 1904 | static const struct ethtool_ops ql3xxx_ethtool_ops = { |
1628 | .get_settings = ql_get_settings, | 1905 | .get_settings = ql_get_settings, |
1629 | .get_drvinfo = ql_get_drvinfo, | 1906 | .get_drvinfo = ql_get_drvinfo, |
@@ -1631,6 +1908,7 @@ static const struct ethtool_ops ql3xxx_ethtool_ops = { | |||
1631 | .get_link = ethtool_op_get_link, | 1908 | .get_link = ethtool_op_get_link, |
1632 | .get_msglevel = ql_get_msglevel, | 1909 | .get_msglevel = ql_get_msglevel, |
1633 | .set_msglevel = ql_set_msglevel, | 1910 | .set_msglevel = ql_set_msglevel, |
1911 | .get_pauseparam = ql_get_pauseparam, | ||
1634 | }; | 1912 | }; |
1635 | 1913 | ||
1636 | static int ql_populate_free_queue(struct ql3_adapter *qdev) | 1914 | static int ql_populate_free_queue(struct ql3_adapter *qdev) |
@@ -1815,14 +2093,14 @@ invalid_seg_count: | |||
1815 | atomic_inc(&qdev->tx_count); | 2093 | atomic_inc(&qdev->tx_count); |
1816 | } | 2094 | } |
1817 | 2095 | ||
1818 | void ql_get_sbuf(struct ql3_adapter *qdev) | 2096 | static void ql_get_sbuf(struct ql3_adapter *qdev) |
1819 | { | 2097 | { |
1820 | if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) | 2098 | if (++qdev->small_buf_index == NUM_SMALL_BUFFERS) |
1821 | qdev->small_buf_index = 0; | 2099 | qdev->small_buf_index = 0; |
1822 | qdev->small_buf_release_cnt++; | 2100 | qdev->small_buf_release_cnt++; |
1823 | } | 2101 | } |
1824 | 2102 | ||
1825 | struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) | 2103 | static struct ql_rcv_buf_cb *ql_get_lbuf(struct ql3_adapter *qdev) |
1826 | { | 2104 | { |
1827 | struct ql_rcv_buf_cb *lrg_buf_cb = NULL; | 2105 | struct ql_rcv_buf_cb *lrg_buf_cb = NULL; |
1828 | lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index]; | 2106 | lrg_buf_cb = &qdev->lrg_buf[qdev->lrg_buf_index]; |
@@ -3074,6 +3352,7 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev) | |||
3074 | goto out; | 3352 | goto out; |
3075 | } | 3353 | } |
3076 | 3354 | ||
3355 | PHY_Setup(qdev); | ||
3077 | ql_init_scan_mode(qdev); | 3356 | ql_init_scan_mode(qdev); |
3078 | ql_get_phy_owner(qdev); | 3357 | ql_get_phy_owner(qdev); |
3079 | 3358 | ||
diff --git a/drivers/net/qla3xxx.h b/drivers/net/qla3xxx.h index 0203f88f0544..4a832c46c274 100755 --- a/drivers/net/qla3xxx.h +++ b/drivers/net/qla3xxx.h | |||
@@ -293,6 +293,16 @@ struct net_rsp_iocb { | |||
293 | 293 | ||
294 | #define MII_SCAN_REGISTER 0x00000001 | 294 | #define MII_SCAN_REGISTER 0x00000001 |
295 | 295 | ||
296 | #define PHY_ID_0_REG 2 | ||
297 | #define PHY_ID_1_REG 3 | ||
298 | |||
299 | #define PHY_OUI_1_MASK 0xfc00 | ||
300 | #define PHY_MODEL_MASK 0x03f0 | ||
301 | |||
302 | /* Address for the Agere Phy */ | ||
303 | #define MII_AGERE_ADDR_1 0x00001000 | ||
304 | #define MII_AGERE_ADDR_2 0x00001100 | ||
305 | |||
296 | /* 32-bit ispControlStatus */ | 306 | /* 32-bit ispControlStatus */ |
297 | enum { | 307 | enum { |
298 | ISP_CONTROL_NP_MASK = 0x0003, | 308 | ISP_CONTROL_NP_MASK = 0x0003, |
@@ -789,6 +799,7 @@ enum { | |||
789 | PHY_CTRL_LOOPBACK = 0x4000, | 799 | PHY_CTRL_LOOPBACK = 0x4000, |
790 | 800 | ||
791 | PETBI_CONTROL_REG = 0x00, | 801 | PETBI_CONTROL_REG = 0x00, |
802 | PETBI_CTRL_ALL_PARAMS = 0x7140, | ||
792 | PETBI_CTRL_SOFT_RESET = 0x8000, | 803 | PETBI_CTRL_SOFT_RESET = 0x8000, |
793 | PETBI_CTRL_AUTO_NEG = 0x1000, | 804 | PETBI_CTRL_AUTO_NEG = 0x1000, |
794 | PETBI_CTRL_RESTART_NEG = 0x0200, | 805 | PETBI_CTRL_RESTART_NEG = 0x0200, |
@@ -811,6 +822,23 @@ enum { | |||
811 | PETBI_EXPANSION_REG = 0x06, | 822 | PETBI_EXPANSION_REG = 0x06, |
812 | PETBI_EXP_PAGE_RX = 0x0002, | 823 | PETBI_EXP_PAGE_RX = 0x0002, |
813 | 824 | ||
825 | PHY_GIG_CONTROL = 9, | ||
826 | PHY_GIG_ENABLE_MAN = 0x1000, /* Enable Master/Slave Manual Config*/ | ||
827 | PHY_GIG_SET_MASTER = 0x0800, /* Set Master (slave if clear)*/ | ||
828 | PHY_GIG_ALL_PARAMS = 0x0300, | ||
829 | PHY_GIG_ADV_1000F = 0x0200, | ||
830 | PHY_GIG_ADV_1000H = 0x0100, | ||
831 | |||
832 | PHY_NEG_ADVER = 4, | ||
833 | PHY_NEG_ALL_PARAMS = 0x0fe0, | ||
834 | PHY_NEG_ASY_PAUSE = 0x0800, | ||
835 | PHY_NEG_SYM_PAUSE = 0x0400, | ||
836 | PHY_NEG_ADV_SPEED = 0x01e0, | ||
837 | PHY_NEG_ADV_100F = 0x0100, | ||
838 | PHY_NEG_ADV_100H = 0x0080, | ||
839 | PHY_NEG_ADV_10F = 0x0040, | ||
840 | PHY_NEG_ADV_10H = 0x0020, | ||
841 | |||
814 | PETBI_TBI_CTRL = 0x11, | 842 | PETBI_TBI_CTRL = 0x11, |
815 | PETBI_TBI_RESET = 0x8000, | 843 | PETBI_TBI_RESET = 0x8000, |
816 | PETBI_TBI_AUTO_SENSE = 0x0100, | 844 | PETBI_TBI_AUTO_SENSE = 0x0100, |
@@ -826,8 +854,7 @@ enum { | |||
826 | PHY_AUX_RESET_STICK = 0x0002, | 854 | PHY_AUX_RESET_STICK = 0x0002, |
827 | PHY_NEG_PAUSE = 0x0400, | 855 | PHY_NEG_PAUSE = 0x0400, |
828 | PHY_CTRL_SOFT_RESET = 0x8000, | 856 | PHY_CTRL_SOFT_RESET = 0x8000, |
829 | PHY_NEG_ADVER = 4, | 857 | PHY_CTRL_AUTO_NEG = 0x1000, |
830 | PHY_NEG_ADV_SPEED = 0x01e0, | ||
831 | PHY_CTRL_RESTART_NEG = 0x0200, | 858 | PHY_CTRL_RESTART_NEG = 0x0200, |
832 | }; | 859 | }; |
833 | enum { | 860 | enum { |
@@ -892,6 +919,7 @@ enum {EEPROM_SIZE = FM93C86A_SIZE_16, | |||
892 | u16 pauseThreshold_mac; | 919 | u16 pauseThreshold_mac; |
893 | u16 resumeThreshold_mac; | 920 | u16 resumeThreshold_mac; |
894 | u16 portConfiguration; | 921 | u16 portConfiguration; |
922 | #define PORT_CONFIG_DEFAULT 0xf700 | ||
895 | #define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000 | 923 | #define PORT_CONFIG_AUTO_NEG_ENABLED 0x8000 |
896 | #define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000 | 924 | #define PORT_CONFIG_SYM_PAUSE_ENABLED 0x4000 |
897 | #define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000 | 925 | #define PORT_CONFIG_FULL_DUPLEX_ENABLED 0x2000 |
@@ -1259,6 +1287,7 @@ struct ql3_adapter { | |||
1259 | struct delayed_work tx_timeout_work; | 1287 | struct delayed_work tx_timeout_work; |
1260 | u32 max_frame_size; | 1288 | u32 max_frame_size; |
1261 | u32 device_id; | 1289 | u32 device_id; |
1290 | u16 phyType; | ||
1262 | }; | 1291 | }; |
1263 | 1292 | ||
1264 | #endif /* _QLA3XXX_H_ */ | 1293 | #endif /* _QLA3XXX_H_ */ |
diff --git a/drivers/net/s2io-regs.h b/drivers/net/s2io-regs.h index 33fb7f3b7041..4cb710bbe729 100644 --- a/drivers/net/s2io-regs.h +++ b/drivers/net/s2io-regs.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /************************************************************************ | 1 | /************************************************************************ |
2 | * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC | 2 | * regs.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC |
3 | * Copyright(c) 2002-2005 Neterion Inc. | 3 | * Copyright(c) 2002-2007 Neterion Inc. |
4 | 4 | ||
5 | * This software may be used and distributed according to the terms of | 5 | * This software may be used and distributed according to the terms of |
6 | * the GNU General Public License (GPL), incorporated herein by reference. | 6 | * the GNU General Public License (GPL), incorporated herein by reference. |
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 600d3ff347fc..290e1c1f30c6 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /************************************************************************ | 1 | /************************************************************************ |
2 | * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC | 2 | * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC |
3 | * Copyright(c) 2002-2005 Neterion Inc. | 3 | * Copyright(c) 2002-2007 Neterion Inc. |
4 | 4 | ||
5 | * This software may be used and distributed according to the terms of | 5 | * This software may be used and distributed according to the terms of |
6 | * the GNU General Public License (GPL), incorporated herein by reference. | 6 | * the GNU General Public License (GPL), incorporated herein by reference. |
@@ -84,7 +84,7 @@ | |||
84 | #include "s2io.h" | 84 | #include "s2io.h" |
85 | #include "s2io-regs.h" | 85 | #include "s2io-regs.h" |
86 | 86 | ||
87 | #define DRV_VERSION "2.0.17.1" | 87 | #define DRV_VERSION "2.0.22.1" |
88 | 88 | ||
89 | /* S2io Driver name & version. */ | 89 | /* S2io Driver name & version. */ |
90 | static char s2io_driver_name[] = "Neterion"; | 90 | static char s2io_driver_name[] = "Neterion"; |
@@ -316,7 +316,7 @@ static void s2io_vlan_rx_register(struct net_device *dev, | |||
316 | } | 316 | } |
317 | 317 | ||
318 | /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */ | 318 | /* A flag indicating whether 'RX_PA_CFG_STRIP_VLAN_TAG' bit is set or not */ |
319 | int vlan_strip_flag; | 319 | static int vlan_strip_flag; |
320 | 320 | ||
321 | /* Unregister the vlan */ | 321 | /* Unregister the vlan */ |
322 | static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) | 322 | static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) |
@@ -394,7 +394,6 @@ static const u64 fix_mac[] = { | |||
394 | END_SIGN | 394 | END_SIGN |
395 | }; | 395 | }; |
396 | 396 | ||
397 | MODULE_AUTHOR("Raghavendra Koushik <raghavendra.koushik@neterion.com>"); | ||
398 | MODULE_LICENSE("GPL"); | 397 | MODULE_LICENSE("GPL"); |
399 | MODULE_VERSION(DRV_VERSION); | 398 | MODULE_VERSION(DRV_VERSION); |
400 | 399 | ||
@@ -516,7 +515,7 @@ static int init_shared_mem(struct s2io_nic *nic) | |||
516 | mac_control->fifos[i].list_info = kmalloc(list_holder_size, | 515 | mac_control->fifos[i].list_info = kmalloc(list_holder_size, |
517 | GFP_KERNEL); | 516 | GFP_KERNEL); |
518 | if (!mac_control->fifos[i].list_info) { | 517 | if (!mac_control->fifos[i].list_info) { |
519 | DBG_PRINT(ERR_DBG, | 518 | DBG_PRINT(INFO_DBG, |
520 | "Malloc failed for list_info\n"); | 519 | "Malloc failed for list_info\n"); |
521 | return -ENOMEM; | 520 | return -ENOMEM; |
522 | } | 521 | } |
@@ -542,9 +541,9 @@ static int init_shared_mem(struct s2io_nic *nic) | |||
542 | tmp_v = pci_alloc_consistent(nic->pdev, | 541 | tmp_v = pci_alloc_consistent(nic->pdev, |
543 | PAGE_SIZE, &tmp_p); | 542 | PAGE_SIZE, &tmp_p); |
544 | if (!tmp_v) { | 543 | if (!tmp_v) { |
545 | DBG_PRINT(ERR_DBG, | 544 | DBG_PRINT(INFO_DBG, |
546 | "pci_alloc_consistent "); | 545 | "pci_alloc_consistent "); |
547 | DBG_PRINT(ERR_DBG, "failed for TxDL\n"); | 546 | DBG_PRINT(INFO_DBG, "failed for TxDL\n"); |
548 | return -ENOMEM; | 547 | return -ENOMEM; |
549 | } | 548 | } |
550 | /* If we got a zero DMA address(can happen on | 549 | /* If we got a zero DMA address(can happen on |
@@ -561,9 +560,9 @@ static int init_shared_mem(struct s2io_nic *nic) | |||
561 | tmp_v = pci_alloc_consistent(nic->pdev, | 560 | tmp_v = pci_alloc_consistent(nic->pdev, |
562 | PAGE_SIZE, &tmp_p); | 561 | PAGE_SIZE, &tmp_p); |
563 | if (!tmp_v) { | 562 | if (!tmp_v) { |
564 | DBG_PRINT(ERR_DBG, | 563 | DBG_PRINT(INFO_DBG, |
565 | "pci_alloc_consistent "); | 564 | "pci_alloc_consistent "); |
566 | DBG_PRINT(ERR_DBG, "failed for TxDL\n"); | 565 | DBG_PRINT(INFO_DBG, "failed for TxDL\n"); |
567 | return -ENOMEM; | 566 | return -ENOMEM; |
568 | } | 567 | } |
569 | } | 568 | } |
@@ -2187,7 +2186,7 @@ static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \ | |||
2187 | /* skb_shinfo(skb)->frag_list will have L4 data payload */ | 2186 | /* skb_shinfo(skb)->frag_list will have L4 data payload */ |
2188 | skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE); | 2187 | skb_shinfo(skb)->frag_list = dev_alloc_skb(dev->mtu + ALIGN_SIZE); |
2189 | if (skb_shinfo(skb)->frag_list == NULL) { | 2188 | if (skb_shinfo(skb)->frag_list == NULL) { |
2190 | DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n ", dev->name); | 2189 | DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n ", dev->name); |
2191 | return -ENOMEM ; | 2190 | return -ENOMEM ; |
2192 | } | 2191 | } |
2193 | frag_list = skb_shinfo(skb)->frag_list; | 2192 | frag_list = skb_shinfo(skb)->frag_list; |
@@ -2242,6 +2241,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) | |||
2242 | struct buffAdd *ba; | 2241 | struct buffAdd *ba; |
2243 | unsigned long flags; | 2242 | unsigned long flags; |
2244 | struct RxD_t *first_rxdp = NULL; | 2243 | struct RxD_t *first_rxdp = NULL; |
2244 | u64 Buffer0_ptr = 0, Buffer1_ptr = 0; | ||
2245 | 2245 | ||
2246 | mac_control = &nic->mac_control; | 2246 | mac_control = &nic->mac_control; |
2247 | config = &nic->config; | 2247 | config = &nic->config; |
@@ -2313,8 +2313,8 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) | |||
2313 | /* allocate skb */ | 2313 | /* allocate skb */ |
2314 | skb = dev_alloc_skb(size); | 2314 | skb = dev_alloc_skb(size); |
2315 | if(!skb) { | 2315 | if(!skb) { |
2316 | DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); | 2316 | DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); |
2317 | DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n"); | 2317 | DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); |
2318 | if (first_rxdp) { | 2318 | if (first_rxdp) { |
2319 | wmb(); | 2319 | wmb(); |
2320 | first_rxdp->Control_1 |= RXD_OWN_XENA; | 2320 | first_rxdp->Control_1 |= RXD_OWN_XENA; |
@@ -2342,7 +2342,14 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no) | |||
2342 | * payload | 2342 | * payload |
2343 | */ | 2343 | */ |
2344 | 2344 | ||
2345 | /* save the buffer pointers to avoid frequent dma mapping */ | ||
2346 | Buffer0_ptr = ((struct RxD3*)rxdp)->Buffer0_ptr; | ||
2347 | Buffer1_ptr = ((struct RxD3*)rxdp)->Buffer1_ptr; | ||
2345 | memset(rxdp, 0, sizeof(struct RxD3)); | 2348 | memset(rxdp, 0, sizeof(struct RxD3)); |
2349 | /* restore the buffer pointers for dma sync*/ | ||
2350 | ((struct RxD3*)rxdp)->Buffer0_ptr = Buffer0_ptr; | ||
2351 | ((struct RxD3*)rxdp)->Buffer1_ptr = Buffer1_ptr; | ||
2352 | |||
2346 | ba = &mac_control->rings[ring_no].ba[block_no][off]; | 2353 | ba = &mac_control->rings[ring_no].ba[block_no][off]; |
2347 | skb_reserve(skb, BUF0_LEN); | 2354 | skb_reserve(skb, BUF0_LEN); |
2348 | tmp = (u64)(unsigned long) skb->data; | 2355 | tmp = (u64)(unsigned long) skb->data; |
@@ -2573,8 +2580,8 @@ static int s2io_poll(struct net_device *dev, int *budget) | |||
2573 | 2580 | ||
2574 | for (i = 0; i < config->rx_ring_num; i++) { | 2581 | for (i = 0; i < config->rx_ring_num; i++) { |
2575 | if (fill_rx_buffers(nic, i) == -ENOMEM) { | 2582 | if (fill_rx_buffers(nic, i) == -ENOMEM) { |
2576 | DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); | 2583 | DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); |
2577 | DBG_PRINT(ERR_DBG, " in Rx Poll!!\n"); | 2584 | DBG_PRINT(INFO_DBG, " in Rx Poll!!\n"); |
2578 | break; | 2585 | break; |
2579 | } | 2586 | } |
2580 | } | 2587 | } |
@@ -2590,8 +2597,8 @@ no_rx: | |||
2590 | 2597 | ||
2591 | for (i = 0; i < config->rx_ring_num; i++) { | 2598 | for (i = 0; i < config->rx_ring_num; i++) { |
2592 | if (fill_rx_buffers(nic, i) == -ENOMEM) { | 2599 | if (fill_rx_buffers(nic, i) == -ENOMEM) { |
2593 | DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); | 2600 | DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); |
2594 | DBG_PRINT(ERR_DBG, " in Rx Poll!!\n"); | 2601 | DBG_PRINT(INFO_DBG, " in Rx Poll!!\n"); |
2595 | break; | 2602 | break; |
2596 | } | 2603 | } |
2597 | } | 2604 | } |
@@ -2640,8 +2647,8 @@ static void s2io_netpoll(struct net_device *dev) | |||
2640 | 2647 | ||
2641 | for (i = 0; i < config->rx_ring_num; i++) { | 2648 | for (i = 0; i < config->rx_ring_num; i++) { |
2642 | if (fill_rx_buffers(nic, i) == -ENOMEM) { | 2649 | if (fill_rx_buffers(nic, i) == -ENOMEM) { |
2643 | DBG_PRINT(ERR_DBG, "%s:Out of memory", dev->name); | 2650 | DBG_PRINT(INFO_DBG, "%s:Out of memory", dev->name); |
2644 | DBG_PRINT(ERR_DBG, " in Rx Netpoll!!\n"); | 2651 | DBG_PRINT(INFO_DBG, " in Rx Netpoll!!\n"); |
2645 | break; | 2652 | break; |
2646 | } | 2653 | } |
2647 | } | 2654 | } |
@@ -3307,6 +3314,7 @@ static void s2io_reset(struct s2io_nic * sp) | |||
3307 | u16 subid, pci_cmd; | 3314 | u16 subid, pci_cmd; |
3308 | int i; | 3315 | int i; |
3309 | u16 val16; | 3316 | u16 val16; |
3317 | unsigned long long reset_cnt = 0; | ||
3310 | DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", | 3318 | DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n", |
3311 | __FUNCTION__, sp->dev->name); | 3319 | __FUNCTION__, sp->dev->name); |
3312 | 3320 | ||
@@ -3372,6 +3380,11 @@ new_way: | |||
3372 | 3380 | ||
3373 | /* Reset device statistics maintained by OS */ | 3381 | /* Reset device statistics maintained by OS */ |
3374 | memset(&sp->stats, 0, sizeof (struct net_device_stats)); | 3382 | memset(&sp->stats, 0, sizeof (struct net_device_stats)); |
3383 | /* save reset count */ | ||
3384 | reset_cnt = sp->mac_control.stats_info->sw_stat.soft_reset_cnt; | ||
3385 | memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); | ||
3386 | /* restore reset count */ | ||
3387 | sp->mac_control.stats_info->sw_stat.soft_reset_cnt = reset_cnt; | ||
3375 | 3388 | ||
3376 | /* SXE-002: Configure link and activity LED to turn it off */ | 3389 | /* SXE-002: Configure link and activity LED to turn it off */ |
3377 | subid = sp->pdev->subsystem_device; | 3390 | subid = sp->pdev->subsystem_device; |
@@ -3659,7 +3672,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) | |||
3659 | nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), | 3672 | nic->entries = kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct msix_entry), |
3660 | GFP_KERNEL); | 3673 | GFP_KERNEL); |
3661 | if (nic->entries == NULL) { | 3674 | if (nic->entries == NULL) { |
3662 | DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); | 3675 | DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); |
3663 | return -ENOMEM; | 3676 | return -ENOMEM; |
3664 | } | 3677 | } |
3665 | memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); | 3678 | memset(nic->entries, 0, MAX_REQUESTED_MSI_X * sizeof(struct msix_entry)); |
@@ -3668,7 +3681,7 @@ static int s2io_enable_msi_x(struct s2io_nic *nic) | |||
3668 | kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), | 3681 | kmalloc(MAX_REQUESTED_MSI_X * sizeof(struct s2io_msix_entry), |
3669 | GFP_KERNEL); | 3682 | GFP_KERNEL); |
3670 | if (nic->s2io_entries == NULL) { | 3683 | if (nic->s2io_entries == NULL) { |
3671 | DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", __FUNCTION__); | 3684 | DBG_PRINT(INFO_DBG, "%s: Memory allocation failed\n", __FUNCTION__); |
3672 | kfree(nic->entries); | 3685 | kfree(nic->entries); |
3673 | return -ENOMEM; | 3686 | return -ENOMEM; |
3674 | } | 3687 | } |
@@ -4019,7 +4032,7 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n) | |||
4019 | DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); | 4032 | DBG_PRINT(INTR_DBG, "%s: Rx BD hit ", __FUNCTION__); |
4020 | DBG_PRINT(INTR_DBG, "PANIC levels\n"); | 4033 | DBG_PRINT(INTR_DBG, "PANIC levels\n"); |
4021 | if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { | 4034 | if ((ret = fill_rx_buffers(sp, rng_n)) == -ENOMEM) { |
4022 | DBG_PRINT(ERR_DBG, "Out of memory in %s", | 4035 | DBG_PRINT(INFO_DBG, "Out of memory in %s", |
4023 | __FUNCTION__); | 4036 | __FUNCTION__); |
4024 | clear_bit(0, (&sp->tasklet_status)); | 4037 | clear_bit(0, (&sp->tasklet_status)); |
4025 | return -1; | 4038 | return -1; |
@@ -4029,8 +4042,8 @@ static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n) | |||
4029 | tasklet_schedule(&sp->task); | 4042 | tasklet_schedule(&sp->task); |
4030 | 4043 | ||
4031 | } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { | 4044 | } else if (fill_rx_buffers(sp, rng_n) == -ENOMEM) { |
4032 | DBG_PRINT(ERR_DBG, "%s:Out of memory", sp->dev->name); | 4045 | DBG_PRINT(INFO_DBG, "%s:Out of memory", sp->dev->name); |
4033 | DBG_PRINT(ERR_DBG, " in Rx Intr!!\n"); | 4046 | DBG_PRINT(INFO_DBG, " in Rx Intr!!\n"); |
4034 | } | 4047 | } |
4035 | return 0; | 4048 | return 0; |
4036 | } | 4049 | } |
@@ -4279,9 +4292,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) | |||
4279 | if (cnt == 5) | 4292 | if (cnt == 5) |
4280 | break; /* Updt failed */ | 4293 | break; /* Updt failed */ |
4281 | } while(1); | 4294 | } while(1); |
4282 | } else { | 4295 | } |
4283 | memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block)); | ||
4284 | } | ||
4285 | } | 4296 | } |
4286 | 4297 | ||
4287 | /** | 4298 | /** |
@@ -5949,12 +5960,12 @@ static void s2io_tasklet(unsigned long dev_addr) | |||
5949 | for (i = 0; i < config->rx_ring_num; i++) { | 5960 | for (i = 0; i < config->rx_ring_num; i++) { |
5950 | ret = fill_rx_buffers(sp, i); | 5961 | ret = fill_rx_buffers(sp, i); |
5951 | if (ret == -ENOMEM) { | 5962 | if (ret == -ENOMEM) { |
5952 | DBG_PRINT(ERR_DBG, "%s: Out of ", | 5963 | DBG_PRINT(INFO_DBG, "%s: Out of ", |
5953 | dev->name); | 5964 | dev->name); |
5954 | DBG_PRINT(ERR_DBG, "memory in tasklet\n"); | 5965 | DBG_PRINT(ERR_DBG, "memory in tasklet\n"); |
5955 | break; | 5966 | break; |
5956 | } else if (ret == -EFILL) { | 5967 | } else if (ret == -EFILL) { |
5957 | DBG_PRINT(ERR_DBG, | 5968 | DBG_PRINT(INFO_DBG, |
5958 | "%s: Rx Ring %d is full\n", | 5969 | "%s: Rx Ring %d is full\n", |
5959 | dev->name, i); | 5970 | dev->name, i); |
5960 | break; | 5971 | break; |
@@ -6065,8 +6076,8 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, | |||
6065 | } else { | 6076 | } else { |
6066 | *skb = dev_alloc_skb(size); | 6077 | *skb = dev_alloc_skb(size); |
6067 | if (!(*skb)) { | 6078 | if (!(*skb)) { |
6068 | DBG_PRINT(ERR_DBG, "%s: Out of ", dev->name); | 6079 | DBG_PRINT(INFO_DBG, "%s: Out of ", dev->name); |
6069 | DBG_PRINT(ERR_DBG, "memory to allocate SKBs\n"); | 6080 | DBG_PRINT(INFO_DBG, "memory to allocate SKBs\n"); |
6070 | return -ENOMEM ; | 6081 | return -ENOMEM ; |
6071 | } | 6082 | } |
6072 | /* storing the mapped addr in a temp variable | 6083 | /* storing the mapped addr in a temp variable |
@@ -6088,7 +6099,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, | |||
6088 | } else { | 6099 | } else { |
6089 | *skb = dev_alloc_skb(size); | 6100 | *skb = dev_alloc_skb(size); |
6090 | if (!(*skb)) { | 6101 | if (!(*skb)) { |
6091 | DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", | 6102 | DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n", |
6092 | dev->name); | 6103 | dev->name); |
6093 | return -ENOMEM; | 6104 | return -ENOMEM; |
6094 | } | 6105 | } |
@@ -6115,7 +6126,7 @@ static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp, | |||
6115 | } else { | 6126 | } else { |
6116 | *skb = dev_alloc_skb(size); | 6127 | *skb = dev_alloc_skb(size); |
6117 | if (!(*skb)) { | 6128 | if (!(*skb)) { |
6118 | DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n", | 6129 | DBG_PRINT(INFO_DBG, "%s: dev_alloc_skb failed\n", |
6119 | dev->name); | 6130 | dev->name); |
6120 | return -ENOMEM; | 6131 | return -ENOMEM; |
6121 | } | 6132 | } |
@@ -6616,7 +6627,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) | |||
6616 | 6627 | ||
6617 | /* Updating statistics */ | 6628 | /* Updating statistics */ |
6618 | rxdp->Host_Control = 0; | 6629 | rxdp->Host_Control = 0; |
6619 | sp->rx_pkt_count++; | ||
6620 | sp->stats.rx_packets++; | 6630 | sp->stats.rx_packets++; |
6621 | if (sp->rxd_mode == RXD_MODE_1) { | 6631 | if (sp->rxd_mode == RXD_MODE_1) { |
6622 | int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); | 6632 | int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2); |
@@ -7252,7 +7262,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) | |||
7252 | goto register_failed; | 7262 | goto register_failed; |
7253 | } | 7263 | } |
7254 | s2io_vpd_read(sp); | 7264 | s2io_vpd_read(sp); |
7255 | DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2005 Neterion Inc.\n"); | 7265 | DBG_PRINT(ERR_DBG, "Copyright(c) 2002-2007 Neterion Inc.\n"); |
7256 | DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name, | 7266 | DBG_PRINT(ERR_DBG, "%s: Neterion %s (rev %d)\n",dev->name, |
7257 | sp->product_name, get_xena_rev_id(sp->pdev)); | 7267 | sp->product_name, get_xena_rev_id(sp->pdev)); |
7258 | DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, | 7268 | DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, |
diff --git a/drivers/net/s2io.h b/drivers/net/s2io.h index 803137ca4b6c..a656d18b33df 100644 --- a/drivers/net/s2io.h +++ b/drivers/net/s2io.h | |||
@@ -1,6 +1,6 @@ | |||
1 | /************************************************************************ | 1 | /************************************************************************ |
2 | * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC | 2 | * s2io.h: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC |
3 | * Copyright(c) 2002-2005 Neterion Inc. | 3 | * Copyright(c) 2002-2007 Neterion Inc. |
4 | 4 | ||
5 | * This software may be used and distributed according to the terms of | 5 | * This software may be used and distributed according to the terms of |
6 | * the GNU General Public License (GPL), incorporated herein by reference. | 6 | * the GNU General Public License (GPL), incorporated herein by reference. |
@@ -760,7 +760,6 @@ struct s2io_nic { | |||
760 | #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED | 760 | #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED |
761 | 761 | ||
762 | struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED]; | 762 | struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED]; |
763 | struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED]; | ||
764 | 763 | ||
765 | struct net_device_stats stats; | 764 | struct net_device_stats stats; |
766 | int high_dma_flag; | 765 | int high_dma_flag; |
@@ -794,11 +793,6 @@ struct s2io_nic { | |||
794 | u16 all_multi_pos; | 793 | u16 all_multi_pos; |
795 | u16 promisc_flg; | 794 | u16 promisc_flg; |
796 | 795 | ||
797 | u16 tx_pkt_count; | ||
798 | u16 rx_pkt_count; | ||
799 | u16 tx_err_count; | ||
800 | u16 rx_err_count; | ||
801 | |||
802 | /* Id timer, used to blink NIC to physically identify NIC. */ | 796 | /* Id timer, used to blink NIC to physically identify NIC. */ |
803 | struct timer_list id_timer; | 797 | struct timer_list id_timer; |
804 | 798 | ||
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 0a3a379b634c..132e2148b21c 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c | |||
@@ -95,19 +95,28 @@ MODULE_PARM_DESC(full_duplex, "1-" __MODULE_STRING(MAX_UNITS)); | |||
95 | #endif | 95 | #endif |
96 | 96 | ||
97 | #ifdef CONFIG_SBMAC_COALESCE | 97 | #ifdef CONFIG_SBMAC_COALESCE |
98 | static int int_pktcnt = 0; | 98 | static int int_pktcnt_tx = 255; |
99 | module_param(int_pktcnt, int, S_IRUGO); | 99 | module_param(int_pktcnt_tx, int, S_IRUGO); |
100 | MODULE_PARM_DESC(int_pktcnt, "Packet count"); | 100 | MODULE_PARM_DESC(int_pktcnt_tx, "TX packet count"); |
101 | 101 | ||
102 | static int int_timeout = 0; | 102 | static int int_timeout_tx = 255; |
103 | module_param(int_timeout, int, S_IRUGO); | 103 | module_param(int_timeout_tx, int, S_IRUGO); |
104 | MODULE_PARM_DESC(int_timeout, "Timeout value"); | 104 | MODULE_PARM_DESC(int_timeout_tx, "TX timeout value"); |
105 | |||
106 | static int int_pktcnt_rx = 64; | ||
107 | module_param(int_pktcnt_rx, int, S_IRUGO); | ||
108 | MODULE_PARM_DESC(int_pktcnt_rx, "RX packet count"); | ||
109 | |||
110 | static int int_timeout_rx = 64; | ||
111 | module_param(int_timeout_rx, int, S_IRUGO); | ||
112 | MODULE_PARM_DESC(int_timeout_rx, "RX timeout value"); | ||
105 | #endif | 113 | #endif |
106 | 114 | ||
107 | #include <asm/sibyte/sb1250.h> | 115 | #include <asm/sibyte/sb1250.h> |
108 | #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) | 116 | #if defined(CONFIG_SIBYTE_BCM1x55) || defined(CONFIG_SIBYTE_BCM1x80) |
109 | #include <asm/sibyte/bcm1480_regs.h> | 117 | #include <asm/sibyte/bcm1480_regs.h> |
110 | #include <asm/sibyte/bcm1480_int.h> | 118 | #include <asm/sibyte/bcm1480_int.h> |
119 | #define R_MAC_DMA_OODPKTLOST_RX R_MAC_DMA_OODPKTLOST | ||
111 | #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) | 120 | #elif defined(CONFIG_SIBYTE_SB1250) || defined(CONFIG_SIBYTE_BCM112X) |
112 | #include <asm/sibyte/sb1250_regs.h> | 121 | #include <asm/sibyte/sb1250_regs.h> |
113 | #include <asm/sibyte/sb1250_int.h> | 122 | #include <asm/sibyte/sb1250_int.h> |
@@ -155,8 +164,8 @@ typedef enum { sbmac_state_uninit, sbmac_state_off, sbmac_state_on, | |||
155 | 164 | ||
156 | #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES) | 165 | #define NUMCACHEBLKS(x) (((x)+SMP_CACHE_BYTES-1)/SMP_CACHE_BYTES) |
157 | 166 | ||
158 | #define SBMAC_MAX_TXDESCR 32 | 167 | #define SBMAC_MAX_TXDESCR 256 |
159 | #define SBMAC_MAX_RXDESCR 32 | 168 | #define SBMAC_MAX_RXDESCR 256 |
160 | 169 | ||
161 | #define ETHER_ALIGN 2 | 170 | #define ETHER_ALIGN 2 |
162 | #define ETHER_ADDR_LEN 6 | 171 | #define ETHER_ADDR_LEN 6 |
@@ -185,10 +194,10 @@ typedef struct sbmacdma_s { | |||
185 | * associated with it. | 194 | * associated with it. |
186 | */ | 195 | */ |
187 | 196 | ||
188 | struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ | 197 | struct sbmac_softc *sbdma_eth; /* back pointer to associated MAC */ |
189 | int sbdma_channel; /* channel number */ | 198 | int sbdma_channel; /* channel number */ |
190 | int sbdma_txdir; /* direction (1=transmit) */ | 199 | int sbdma_txdir; /* direction (1=transmit) */ |
191 | int sbdma_maxdescr; /* total # of descriptors in ring */ | 200 | int sbdma_maxdescr; /* total # of descriptors in ring */ |
192 | #ifdef CONFIG_SBMAC_COALESCE | 201 | #ifdef CONFIG_SBMAC_COALESCE |
193 | int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/ | 202 | int sbdma_int_pktcnt; /* # descriptors rx/tx before interrupt*/ |
194 | int sbdma_int_timeout; /* # usec rx/tx interrupt */ | 203 | int sbdma_int_timeout; /* # usec rx/tx interrupt */ |
@@ -197,13 +206,16 @@ typedef struct sbmacdma_s { | |||
197 | volatile void __iomem *sbdma_config0; /* DMA config register 0 */ | 206 | volatile void __iomem *sbdma_config0; /* DMA config register 0 */ |
198 | volatile void __iomem *sbdma_config1; /* DMA config register 1 */ | 207 | volatile void __iomem *sbdma_config1; /* DMA config register 1 */ |
199 | volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ | 208 | volatile void __iomem *sbdma_dscrbase; /* Descriptor base address */ |
200 | volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ | 209 | volatile void __iomem *sbdma_dscrcnt; /* Descriptor count register */ |
201 | volatile void __iomem *sbdma_curdscr; /* current descriptor address */ | 210 | volatile void __iomem *sbdma_curdscr; /* current descriptor address */ |
211 | volatile void __iomem *sbdma_oodpktlost;/* pkt drop (rx only) */ | ||
212 | |||
202 | 213 | ||
203 | /* | 214 | /* |
204 | * This stuff is for maintenance of the ring | 215 | * This stuff is for maintenance of the ring |
205 | */ | 216 | */ |
206 | 217 | ||
218 | sbdmadscr_t *sbdma_dscrtable_unaligned; | ||
207 | sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ | 219 | sbdmadscr_t *sbdma_dscrtable; /* base of descriptor table */ |
208 | sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ | 220 | sbdmadscr_t *sbdma_dscrtable_end; /* end of descriptor table */ |
209 | 221 | ||
@@ -286,8 +298,8 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *m); | |||
286 | static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m); | 298 | static int sbdma_add_txbuffer(sbmacdma_t *d,struct sk_buff *m); |
287 | static void sbdma_emptyring(sbmacdma_t *d); | 299 | static void sbdma_emptyring(sbmacdma_t *d); |
288 | static void sbdma_fillring(sbmacdma_t *d); | 300 | static void sbdma_fillring(sbmacdma_t *d); |
289 | static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d); | 301 | static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, int work_to_do, int poll); |
290 | static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d); | 302 | static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll); |
291 | static int sbmac_initctx(struct sbmac_softc *s); | 303 | static int sbmac_initctx(struct sbmac_softc *s); |
292 | static void sbmac_channel_start(struct sbmac_softc *s); | 304 | static void sbmac_channel_start(struct sbmac_softc *s); |
293 | static void sbmac_channel_stop(struct sbmac_softc *s); | 305 | static void sbmac_channel_stop(struct sbmac_softc *s); |
@@ -308,6 +320,8 @@ static struct net_device_stats *sbmac_get_stats(struct net_device *dev); | |||
308 | static void sbmac_set_rx_mode(struct net_device *dev); | 320 | static void sbmac_set_rx_mode(struct net_device *dev); |
309 | static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | 321 | static int sbmac_mii_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
310 | static int sbmac_close(struct net_device *dev); | 322 | static int sbmac_close(struct net_device *dev); |
323 | static int sbmac_poll(struct net_device *poll_dev, int *budget); | ||
324 | |||
311 | static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); | 325 | static int sbmac_mii_poll(struct sbmac_softc *s,int noisy); |
312 | static int sbmac_mii_probe(struct net_device *dev); | 326 | static int sbmac_mii_probe(struct net_device *dev); |
313 | 327 | ||
@@ -679,6 +693,10 @@ static void sbdma_initctx(sbmacdma_t *d, | |||
679 | int txrx, | 693 | int txrx, |
680 | int maxdescr) | 694 | int maxdescr) |
681 | { | 695 | { |
696 | #ifdef CONFIG_SBMAC_COALESCE | ||
697 | int int_pktcnt, int_timeout; | ||
698 | #endif | ||
699 | |||
682 | /* | 700 | /* |
683 | * Save away interesting stuff in the structure | 701 | * Save away interesting stuff in the structure |
684 | */ | 702 | */ |
@@ -728,6 +746,11 @@ static void sbdma_initctx(sbmacdma_t *d, | |||
728 | s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT); | 746 | s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_DSCR_CNT); |
729 | d->sbdma_curdscr = | 747 | d->sbdma_curdscr = |
730 | s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR); | 748 | s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_CUR_DSCRADDR); |
749 | if (d->sbdma_txdir) | ||
750 | d->sbdma_oodpktlost = NULL; | ||
751 | else | ||
752 | d->sbdma_oodpktlost = | ||
753 | s->sbm_base + R_MAC_DMA_REGISTER(txrx,chan,R_MAC_DMA_OODPKTLOST_RX); | ||
731 | 754 | ||
732 | /* | 755 | /* |
733 | * Allocate memory for the ring | 756 | * Allocate memory for the ring |
@@ -735,6 +758,7 @@ static void sbdma_initctx(sbmacdma_t *d, | |||
735 | 758 | ||
736 | d->sbdma_maxdescr = maxdescr; | 759 | d->sbdma_maxdescr = maxdescr; |
737 | 760 | ||
761 | d->sbdma_dscrtable_unaligned = | ||
738 | d->sbdma_dscrtable = (sbdmadscr_t *) | 762 | d->sbdma_dscrtable = (sbdmadscr_t *) |
739 | kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); | 763 | kmalloc((d->sbdma_maxdescr+1)*sizeof(sbdmadscr_t), GFP_KERNEL); |
740 | 764 | ||
@@ -765,12 +789,14 @@ static void sbdma_initctx(sbmacdma_t *d, | |||
765 | * Setup Rx/Tx DMA coalescing defaults | 789 | * Setup Rx/Tx DMA coalescing defaults |
766 | */ | 790 | */ |
767 | 791 | ||
792 | int_pktcnt = (txrx == DMA_TX) ? int_pktcnt_tx : int_pktcnt_rx; | ||
768 | if ( int_pktcnt ) { | 793 | if ( int_pktcnt ) { |
769 | d->sbdma_int_pktcnt = int_pktcnt; | 794 | d->sbdma_int_pktcnt = int_pktcnt; |
770 | } else { | 795 | } else { |
771 | d->sbdma_int_pktcnt = 1; | 796 | d->sbdma_int_pktcnt = 1; |
772 | } | 797 | } |
773 | 798 | ||
799 | int_timeout = (txrx == DMA_TX) ? int_timeout_tx : int_timeout_rx; | ||
774 | if ( int_timeout ) { | 800 | if ( int_timeout ) { |
775 | d->sbdma_int_timeout = int_timeout; | 801 | d->sbdma_int_timeout = int_timeout; |
776 | } else { | 802 | } else { |
@@ -1125,32 +1151,63 @@ static void sbdma_fillring(sbmacdma_t *d) | |||
1125 | } | 1151 | } |
1126 | } | 1152 | } |
1127 | 1153 | ||
1154 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
1155 | static void sbmac_netpoll(struct net_device *netdev) | ||
1156 | { | ||
1157 | struct sbmac_softc *sc = netdev_priv(netdev); | ||
1158 | int irq = sc->sbm_dev->irq; | ||
1159 | |||
1160 | __raw_writeq(0, sc->sbm_imr); | ||
1161 | |||
1162 | sbmac_intr(irq, netdev, NULL); | ||
1163 | |||
1164 | #ifdef CONFIG_SBMAC_COALESCE | ||
1165 | __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | | ||
1166 | ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), | ||
1167 | sc->sbm_imr); | ||
1168 | #else | ||
1169 | __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | | ||
1170 | (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr); | ||
1171 | #endif | ||
1172 | } | ||
1173 | #endif | ||
1128 | 1174 | ||
1129 | /********************************************************************** | 1175 | /********************************************************************** |
1130 | * SBDMA_RX_PROCESS(sc,d) | 1176 | * SBDMA_RX_PROCESS(sc,d,work_to_do,poll) |
1131 | * | 1177 | * |
1132 | * Process "completed" receive buffers on the specified DMA channel. | 1178 | * Process "completed" receive buffers on the specified DMA channel. |
1133 | * Note that this isn't really ideal for priority channels, since | ||
1134 | * it processes all of the packets on a given channel before | ||
1135 | * returning. | ||
1136 | * | 1179 | * |
1137 | * Input parameters: | 1180 | * Input parameters: |
1138 | * sc - softc structure | 1181 | * sc - softc structure |
1139 | * d - DMA channel context | 1182 | * d - DMA channel context |
1183 | * work_to_do - no. of packets to process before enabling interrupt | ||
1184 | * again (for NAPI) | ||
1185 | * poll - 1: using polling (for NAPI) | ||
1140 | * | 1186 | * |
1141 | * Return value: | 1187 | * Return value: |
1142 | * nothing | 1188 | * nothing |
1143 | ********************************************************************* */ | 1189 | ********************************************************************* */ |
1144 | 1190 | ||
1145 | static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | 1191 | static int sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d, |
1192 | int work_to_do, int poll) | ||
1146 | { | 1193 | { |
1147 | int curidx; | 1194 | int curidx; |
1148 | int hwidx; | 1195 | int hwidx; |
1149 | sbdmadscr_t *dsc; | 1196 | sbdmadscr_t *dsc; |
1150 | struct sk_buff *sb; | 1197 | struct sk_buff *sb; |
1151 | int len; | 1198 | int len; |
1199 | int work_done = 0; | ||
1200 | int dropped = 0; | ||
1152 | 1201 | ||
1153 | for (;;) { | 1202 | prefetch(d); |
1203 | |||
1204 | again: | ||
1205 | /* Check if the HW dropped any frames */ | ||
1206 | sc->sbm_stats.rx_fifo_errors | ||
1207 | += __raw_readq(sc->sbm_rxdma.sbdma_oodpktlost) & 0xffff; | ||
1208 | __raw_writeq(0, sc->sbm_rxdma.sbdma_oodpktlost); | ||
1209 | |||
1210 | while (work_to_do-- > 0) { | ||
1154 | /* | 1211 | /* |
1155 | * figure out where we are (as an index) and where | 1212 | * figure out where we are (as an index) and where |
1156 | * the hardware is (also as an index) | 1213 | * the hardware is (also as an index) |
@@ -1162,7 +1219,12 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1162 | * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) | 1219 | * (sbdma_remptr) and the physical address (sbdma_curdscr CSR) |
1163 | */ | 1220 | */ |
1164 | 1221 | ||
1165 | curidx = d->sbdma_remptr - d->sbdma_dscrtable; | 1222 | dsc = d->sbdma_remptr; |
1223 | curidx = dsc - d->sbdma_dscrtable; | ||
1224 | |||
1225 | prefetch(dsc); | ||
1226 | prefetch(&d->sbdma_ctxtable[curidx]); | ||
1227 | |||
1166 | hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - | 1228 | hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - |
1167 | d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); | 1229 | d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); |
1168 | 1230 | ||
@@ -1173,13 +1235,12 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1173 | */ | 1235 | */ |
1174 | 1236 | ||
1175 | if (curidx == hwidx) | 1237 | if (curidx == hwidx) |
1176 | break; | 1238 | goto done; |
1177 | 1239 | ||
1178 | /* | 1240 | /* |
1179 | * Otherwise, get the packet's sk_buff ptr back | 1241 | * Otherwise, get the packet's sk_buff ptr back |
1180 | */ | 1242 | */ |
1181 | 1243 | ||
1182 | dsc = &(d->sbdma_dscrtable[curidx]); | ||
1183 | sb = d->sbdma_ctxtable[curidx]; | 1244 | sb = d->sbdma_ctxtable[curidx]; |
1184 | d->sbdma_ctxtable[curidx] = NULL; | 1245 | d->sbdma_ctxtable[curidx] = NULL; |
1185 | 1246 | ||
@@ -1191,7 +1252,7 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1191 | * receive ring. | 1252 | * receive ring. |
1192 | */ | 1253 | */ |
1193 | 1254 | ||
1194 | if (!(dsc->dscr_a & M_DMA_ETHRX_BAD)) { | 1255 | if (likely (!(dsc->dscr_a & M_DMA_ETHRX_BAD))) { |
1195 | 1256 | ||
1196 | /* | 1257 | /* |
1197 | * Add a new buffer to replace the old one. If we fail | 1258 | * Add a new buffer to replace the old one. If we fail |
@@ -1199,9 +1260,14 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1199 | * packet and put it right back on the receive ring. | 1260 | * packet and put it right back on the receive ring. |
1200 | */ | 1261 | */ |
1201 | 1262 | ||
1202 | if (sbdma_add_rcvbuffer(d,NULL) == -ENOBUFS) { | 1263 | if (unlikely (sbdma_add_rcvbuffer(d,NULL) == |
1203 | sc->sbm_stats.rx_dropped++; | 1264 | -ENOBUFS)) { |
1265 | sc->sbm_stats.rx_dropped++; | ||
1204 | sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ | 1266 | sbdma_add_rcvbuffer(d,sb); /* re-add old buffer */ |
1267 | /* No point in continuing at the moment */ | ||
1268 | printk(KERN_ERR "dropped packet (1)\n"); | ||
1269 | d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); | ||
1270 | goto done; | ||
1205 | } else { | 1271 | } else { |
1206 | /* | 1272 | /* |
1207 | * Set length into the packet | 1273 | * Set length into the packet |
@@ -1213,8 +1279,6 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1213 | * receive ring. Pass the buffer to | 1279 | * receive ring. Pass the buffer to |
1214 | * the kernel | 1280 | * the kernel |
1215 | */ | 1281 | */ |
1216 | sc->sbm_stats.rx_bytes += len; | ||
1217 | sc->sbm_stats.rx_packets++; | ||
1218 | sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev); | 1282 | sb->protocol = eth_type_trans(sb,d->sbdma_eth->sbm_dev); |
1219 | /* Check hw IPv4/TCP checksum if supported */ | 1283 | /* Check hw IPv4/TCP checksum if supported */ |
1220 | if (sc->rx_hw_checksum == ENABLE) { | 1284 | if (sc->rx_hw_checksum == ENABLE) { |
@@ -1226,8 +1290,22 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1226 | sb->ip_summed = CHECKSUM_NONE; | 1290 | sb->ip_summed = CHECKSUM_NONE; |
1227 | } | 1291 | } |
1228 | } | 1292 | } |
1229 | 1293 | prefetch(sb->data); | |
1230 | netif_rx(sb); | 1294 | prefetch((const void *)(((char *)sb->data)+32)); |
1295 | if (poll) | ||
1296 | dropped = netif_receive_skb(sb); | ||
1297 | else | ||
1298 | dropped = netif_rx(sb); | ||
1299 | |||
1300 | if (dropped == NET_RX_DROP) { | ||
1301 | sc->sbm_stats.rx_dropped++; | ||
1302 | d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); | ||
1303 | goto done; | ||
1304 | } | ||
1305 | else { | ||
1306 | sc->sbm_stats.rx_bytes += len; | ||
1307 | sc->sbm_stats.rx_packets++; | ||
1308 | } | ||
1231 | } | 1309 | } |
1232 | } else { | 1310 | } else { |
1233 | /* | 1311 | /* |
@@ -1244,12 +1322,16 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1244 | */ | 1322 | */ |
1245 | 1323 | ||
1246 | d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); | 1324 | d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); |
1247 | 1325 | work_done++; | |
1248 | } | 1326 | } |
1327 | if (!poll) { | ||
1328 | work_to_do = 32; | ||
1329 | goto again; /* collect fifo drop statistics again */ | ||
1330 | } | ||
1331 | done: | ||
1332 | return work_done; | ||
1249 | } | 1333 | } |
1250 | 1334 | ||
1251 | |||
1252 | |||
1253 | /********************************************************************** | 1335 | /********************************************************************** |
1254 | * SBDMA_TX_PROCESS(sc,d) | 1336 | * SBDMA_TX_PROCESS(sc,d) |
1255 | * | 1337 | * |
@@ -1261,22 +1343,30 @@ static void sbdma_rx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1261 | * | 1343 | * |
1262 | * Input parameters: | 1344 | * Input parameters: |
1263 | * sc - softc structure | 1345 | * sc - softc structure |
1264 | * d - DMA channel context | 1346 | * d - DMA channel context |
1347 | * poll - 1: using polling (for NAPI) | ||
1265 | * | 1348 | * |
1266 | * Return value: | 1349 | * Return value: |
1267 | * nothing | 1350 | * nothing |
1268 | ********************************************************************* */ | 1351 | ********************************************************************* */ |
1269 | 1352 | ||
1270 | static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) | 1353 | static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d, int poll) |
1271 | { | 1354 | { |
1272 | int curidx; | 1355 | int curidx; |
1273 | int hwidx; | 1356 | int hwidx; |
1274 | sbdmadscr_t *dsc; | 1357 | sbdmadscr_t *dsc; |
1275 | struct sk_buff *sb; | 1358 | struct sk_buff *sb; |
1276 | unsigned long flags; | 1359 | unsigned long flags; |
1360 | int packets_handled = 0; | ||
1277 | 1361 | ||
1278 | spin_lock_irqsave(&(sc->sbm_lock), flags); | 1362 | spin_lock_irqsave(&(sc->sbm_lock), flags); |
1279 | 1363 | ||
1364 | if (d->sbdma_remptr == d->sbdma_addptr) | ||
1365 | goto end_unlock; | ||
1366 | |||
1367 | hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - | ||
1368 | d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); | ||
1369 | |||
1280 | for (;;) { | 1370 | for (;;) { |
1281 | /* | 1371 | /* |
1282 | * figure out where we are (as an index) and where | 1372 | * figure out where we are (as an index) and where |
@@ -1290,8 +1380,6 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1290 | */ | 1380 | */ |
1291 | 1381 | ||
1292 | curidx = d->sbdma_remptr - d->sbdma_dscrtable; | 1382 | curidx = d->sbdma_remptr - d->sbdma_dscrtable; |
1293 | hwidx = (int) (((__raw_readq(d->sbdma_curdscr) & M_DMA_CURDSCR_ADDR) - | ||
1294 | d->sbdma_dscrtable_phys) / sizeof(sbdmadscr_t)); | ||
1295 | 1383 | ||
1296 | /* | 1384 | /* |
1297 | * If they're the same, that means we've processed all | 1385 | * If they're the same, that means we've processed all |
@@ -1329,6 +1417,8 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1329 | 1417 | ||
1330 | d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); | 1418 | d->sbdma_remptr = SBDMA_NEXTBUF(d,sbdma_remptr); |
1331 | 1419 | ||
1420 | packets_handled++; | ||
1421 | |||
1332 | } | 1422 | } |
1333 | 1423 | ||
1334 | /* | 1424 | /* |
@@ -1337,8 +1427,10 @@ static void sbdma_tx_process(struct sbmac_softc *sc,sbmacdma_t *d) | |||
1337 | * watermark on the transmit queue. | 1427 | * watermark on the transmit queue. |
1338 | */ | 1428 | */ |
1339 | 1429 | ||
1340 | netif_wake_queue(d->sbdma_eth->sbm_dev); | 1430 | if (packets_handled) |
1431 | netif_wake_queue(d->sbdma_eth->sbm_dev); | ||
1341 | 1432 | ||
1433 | end_unlock: | ||
1342 | spin_unlock_irqrestore(&(sc->sbm_lock), flags); | 1434 | spin_unlock_irqrestore(&(sc->sbm_lock), flags); |
1343 | 1435 | ||
1344 | } | 1436 | } |
@@ -1412,9 +1504,9 @@ static int sbmac_initctx(struct sbmac_softc *s) | |||
1412 | 1504 | ||
1413 | static void sbdma_uninitctx(struct sbmacdma_s *d) | 1505 | static void sbdma_uninitctx(struct sbmacdma_s *d) |
1414 | { | 1506 | { |
1415 | if (d->sbdma_dscrtable) { | 1507 | if (d->sbdma_dscrtable_unaligned) { |
1416 | kfree(d->sbdma_dscrtable); | 1508 | kfree(d->sbdma_dscrtable_unaligned); |
1417 | d->sbdma_dscrtable = NULL; | 1509 | d->sbdma_dscrtable_unaligned = d->sbdma_dscrtable = NULL; |
1418 | } | 1510 | } |
1419 | 1511 | ||
1420 | if (d->sbdma_ctxtable) { | 1512 | if (d->sbdma_ctxtable) { |
@@ -1612,15 +1704,9 @@ static void sbmac_channel_start(struct sbmac_softc *s) | |||
1612 | #endif | 1704 | #endif |
1613 | 1705 | ||
1614 | #ifdef CONFIG_SBMAC_COALESCE | 1706 | #ifdef CONFIG_SBMAC_COALESCE |
1615 | /* | ||
1616 | * Accept any TX interrupt and EOP count/timer RX interrupts on ch 0 | ||
1617 | */ | ||
1618 | __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | | 1707 | __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | |
1619 | ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr); | 1708 | ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), s->sbm_imr); |
1620 | #else | 1709 | #else |
1621 | /* | ||
1622 | * Accept any kind of interrupt on TX and RX DMA channel 0 | ||
1623 | */ | ||
1624 | __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | | 1710 | __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | |
1625 | (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr); | 1711 | (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), s->sbm_imr); |
1626 | #endif | 1712 | #endif |
@@ -2053,57 +2139,46 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) | |||
2053 | uint64_t isr; | 2139 | uint64_t isr; |
2054 | int handled = 0; | 2140 | int handled = 0; |
2055 | 2141 | ||
2056 | for (;;) { | 2142 | /* |
2057 | 2143 | * Read the ISR (this clears the bits in the real | |
2058 | /* | 2144 | * register, except for counter addr) |
2059 | * Read the ISR (this clears the bits in the real | 2145 | */ |
2060 | * register, except for counter addr) | ||
2061 | */ | ||
2062 | 2146 | ||
2063 | isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; | 2147 | isr = __raw_readq(sc->sbm_isr) & ~M_MAC_COUNTER_ADDR; |
2064 | 2148 | ||
2065 | if (isr == 0) | 2149 | if (isr == 0) |
2066 | break; | 2150 | return IRQ_RETVAL(0); |
2151 | handled = 1; | ||
2067 | 2152 | ||
2068 | handled = 1; | 2153 | /* |
2069 | 2154 | * Transmits on channel 0 | |
2070 | /* | 2155 | */ |
2071 | * Transmits on channel 0 | ||
2072 | */ | ||
2073 | 2156 | ||
2074 | if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { | 2157 | if (isr & (M_MAC_INT_CHANNEL << S_MAC_TX_CH0)) { |
2075 | sbdma_tx_process(sc,&(sc->sbm_txdma)); | 2158 | sbdma_tx_process(sc,&(sc->sbm_txdma), 0); |
2159 | #ifdef CONFIG_NETPOLL_TRAP | ||
2160 | if (netpoll_trap()) { | ||
2161 | if (test_and_clear_bit(__LINK_STATE_XOFF, &dev->state)) | ||
2162 | __netif_schedule(dev); | ||
2076 | } | 2163 | } |
2164 | #endif | ||
2165 | } | ||
2077 | 2166 | ||
2078 | /* | 2167 | if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { |
2079 | * Receives on channel 0 | 2168 | if (netif_rx_schedule_prep(dev)) { |
2080 | */ | 2169 | __raw_writeq(0, sc->sbm_imr); |
2081 | 2170 | __netif_rx_schedule(dev); | |
2082 | /* | 2171 | /* Depend on the exit from poll to reenable intr */ |
2083 | * It's important to test all the bits (or at least the | 2172 | } |
2084 | * EOP_SEEN bit) when deciding to do the RX process | 2173 | else { |
2085 | * particularly when coalescing, to make sure we | 2174 | /* may leave some packets behind */ |
2086 | * take care of the following: | 2175 | sbdma_rx_process(sc,&(sc->sbm_rxdma), |
2087 | * | 2176 | SBMAC_MAX_RXDESCR * 2, 0); |
2088 | * If you have some packets waiting (have been received | ||
2089 | * but no interrupt) and get a TX interrupt before | ||
2090 | * the RX timer or counter expires, reading the ISR | ||
2091 | * above will clear the timer and counter, and you | ||
2092 | * won't get another interrupt until a packet shows | ||
2093 | * up to start the timer again. Testing | ||
2094 | * EOP_SEEN here takes care of this case. | ||
2095 | * (EOP_SEEN is part of M_MAC_INT_CHANNEL << S_MAC_RX_CH0) | ||
2096 | */ | ||
2097 | |||
2098 | |||
2099 | if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { | ||
2100 | sbdma_rx_process(sc,&(sc->sbm_rxdma)); | ||
2101 | } | 2177 | } |
2102 | } | 2178 | } |
2103 | return IRQ_RETVAL(handled); | 2179 | return IRQ_RETVAL(handled); |
2104 | } | 2180 | } |
2105 | 2181 | ||
2106 | |||
2107 | /********************************************************************** | 2182 | /********************************************************************** |
2108 | * SBMAC_START_TX(skb,dev) | 2183 | * SBMAC_START_TX(skb,dev) |
2109 | * | 2184 | * |
@@ -2233,8 +2308,6 @@ static void sbmac_setmulti(struct sbmac_softc *sc) | |||
2233 | } | 2308 | } |
2234 | } | 2309 | } |
2235 | 2310 | ||
2236 | |||
2237 | |||
2238 | #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) | 2311 | #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) |
2239 | /********************************************************************** | 2312 | /********************************************************************** |
2240 | * SBMAC_PARSE_XDIGIT(str) | 2313 | * SBMAC_PARSE_XDIGIT(str) |
@@ -2397,8 +2470,13 @@ static int sbmac_init(struct net_device *dev, int idx) | |||
2397 | dev->do_ioctl = sbmac_mii_ioctl; | 2470 | dev->do_ioctl = sbmac_mii_ioctl; |
2398 | dev->tx_timeout = sbmac_tx_timeout; | 2471 | dev->tx_timeout = sbmac_tx_timeout; |
2399 | dev->watchdog_timeo = TX_TIMEOUT; | 2472 | dev->watchdog_timeo = TX_TIMEOUT; |
2473 | dev->poll = sbmac_poll; | ||
2474 | dev->weight = 16; | ||
2400 | 2475 | ||
2401 | dev->change_mtu = sb1250_change_mtu; | 2476 | dev->change_mtu = sb1250_change_mtu; |
2477 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
2478 | dev->poll_controller = sbmac_netpoll; | ||
2479 | #endif | ||
2402 | 2480 | ||
2403 | /* This is needed for PASS2 for Rx H/W checksum feature */ | 2481 | /* This is needed for PASS2 for Rx H/W checksum feature */ |
2404 | sbmac_set_iphdr_offset(sc); | 2482 | sbmac_set_iphdr_offset(sc); |
@@ -2796,7 +2874,39 @@ static int sbmac_close(struct net_device *dev) | |||
2796 | return 0; | 2874 | return 0; |
2797 | } | 2875 | } |
2798 | 2876 | ||
2877 | static int sbmac_poll(struct net_device *dev, int *budget) | ||
2878 | { | ||
2879 | int work_to_do; | ||
2880 | int work_done; | ||
2881 | struct sbmac_softc *sc = netdev_priv(dev); | ||
2882 | |||
2883 | work_to_do = min(*budget, dev->quota); | ||
2884 | work_done = sbdma_rx_process(sc, &(sc->sbm_rxdma), work_to_do, 1); | ||
2799 | 2885 | ||
2886 | if (work_done > work_to_do) | ||
2887 | printk(KERN_ERR "%s exceeded work_to_do budget=%d quota=%d work-done=%d\n", | ||
2888 | sc->sbm_dev->name, *budget, dev->quota, work_done); | ||
2889 | |||
2890 | sbdma_tx_process(sc, &(sc->sbm_txdma), 1); | ||
2891 | |||
2892 | *budget -= work_done; | ||
2893 | dev->quota -= work_done; | ||
2894 | |||
2895 | if (work_done < work_to_do) { | ||
2896 | netif_rx_complete(dev); | ||
2897 | |||
2898 | #ifdef CONFIG_SBMAC_COALESCE | ||
2899 | __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | | ||
2900 | ((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_RX_CH0), | ||
2901 | sc->sbm_imr); | ||
2902 | #else | ||
2903 | __raw_writeq((M_MAC_INT_CHANNEL << S_MAC_TX_CH0) | | ||
2904 | (M_MAC_INT_CHANNEL << S_MAC_RX_CH0), sc->sbm_imr); | ||
2905 | #endif | ||
2906 | } | ||
2907 | |||
2908 | return (work_done >= work_to_do); | ||
2909 | } | ||
2800 | 2910 | ||
2801 | #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) | 2911 | #if defined(SBMAC_ETH0_HWADDR) || defined(SBMAC_ETH1_HWADDR) || defined(SBMAC_ETH2_HWADDR) || defined(SBMAC_ETH3_HWADDR) |
2802 | static void | 2912 | static void |
@@ -2883,7 +2993,7 @@ sbmac_init_module(void) | |||
2883 | 2993 | ||
2884 | /* | 2994 | /* |
2885 | * The R_MAC_ETHERNET_ADDR register will be set to some nonzero | 2995 | * The R_MAC_ETHERNET_ADDR register will be set to some nonzero |
2886 | * value for us by the firmware if we're going to use this MAC. | 2996 | * value for us by the firmware if we are going to use this MAC. |
2887 | * If we find a zero, skip this MAC. | 2997 | * If we find a zero, skip this MAC. |
2888 | */ | 2998 | */ |
2889 | 2999 | ||
diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index d8c9c5d66d4f..1fc77300b055 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c | |||
@@ -624,7 +624,7 @@ static inline void setup_rx_ring(struct sgiseeq_rx_desc *buf, int nbufs) | |||
624 | 624 | ||
625 | #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) | 625 | #define ALIGNED(x) ((((unsigned long)(x)) + 0xf) & ~(0xf)) |
626 | 626 | ||
627 | static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq) | 627 | static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq, int has_eeprom) |
628 | { | 628 | { |
629 | struct sgiseeq_init_block *sr; | 629 | struct sgiseeq_init_block *sr; |
630 | struct sgiseeq_private *sp; | 630 | struct sgiseeq_private *sp; |
@@ -650,7 +650,9 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq) | |||
650 | 650 | ||
651 | #define EADDR_NVOFS 250 | 651 | #define EADDR_NVOFS 250 |
652 | for (i = 0; i < 3; i++) { | 652 | for (i = 0; i < 3; i++) { |
653 | unsigned short tmp = ip22_nvram_read(EADDR_NVOFS / 2 + i); | 653 | unsigned short tmp = has_eeprom ? |
654 | ip22_eeprom_read(&hpcregs->eeprom, EADDR_NVOFS / 2+i) : | ||
655 | ip22_nvram_read(EADDR_NVOFS / 2+i); | ||
654 | 656 | ||
655 | dev->dev_addr[2 * i] = tmp >> 8; | 657 | dev->dev_addr[2 * i] = tmp >> 8; |
656 | dev->dev_addr[2 * i + 1] = tmp & 0xff; | 658 | dev->dev_addr[2 * i + 1] = tmp & 0xff; |
@@ -683,6 +685,11 @@ static int sgiseeq_init(struct hpc3_regs* hpcregs, int irq) | |||
683 | sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | | 685 | sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | |
684 | HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; | 686 | HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; |
685 | 687 | ||
688 | /* Setup PIO and DMA transfer timing */ | ||
689 | sp->hregs->pconfig = 0x161; | ||
690 | sp->hregs->dconfig = HPC3_EDCFG_FIRQ | HPC3_EDCFG_FEOP | | ||
691 | HPC3_EDCFG_FRXDC | HPC3_EDCFG_PTO | 0x026; | ||
692 | |||
686 | /* Reset the chip. */ | 693 | /* Reset the chip. */ |
687 | hpc3_eth_reset(sp->hregs); | 694 | hpc3_eth_reset(sp->hregs); |
688 | 695 | ||
@@ -729,8 +736,23 @@ err_out: | |||
729 | 736 | ||
730 | static int __init sgiseeq_probe(void) | 737 | static int __init sgiseeq_probe(void) |
731 | { | 738 | { |
739 | unsigned int tmp, ret1, ret2 = 0; | ||
740 | |||
732 | /* On board adapter on 1st HPC is always present */ | 741 | /* On board adapter on 1st HPC is always present */ |
733 | return sgiseeq_init(hpc3c0, SGI_ENET_IRQ); | 742 | ret1 = sgiseeq_init(hpc3c0, SGI_ENET_IRQ, 0); |
743 | /* Let's see if second HPC is there */ | ||
744 | if (!(ip22_is_fullhouse()) && | ||
745 | get_dbe(tmp, (unsigned int *)&hpc3c1->pbdma[1]) == 0) { | ||
746 | sgimc->giopar |= SGIMC_GIOPAR_MASTEREXP1 | | ||
747 | SGIMC_GIOPAR_EXP164 | | ||
748 | SGIMC_GIOPAR_HPC264; | ||
749 | hpc3c1->pbus_piocfg[0][0] = 0x3ffff; | ||
750 | /* interrupt/config register on Challenge S Mezz board */ | ||
751 | hpc3c1->pbus_extregs[0][0] = 0x30; | ||
752 | ret2 = sgiseeq_init(hpc3c1, SGI_GIO_0_IRQ, 1); | ||
753 | } | ||
754 | |||
755 | return (ret1 & ret2) ? ret1 : 0; | ||
734 | } | 756 | } |
735 | 757 | ||
736 | static void __exit sgiseeq_exit(void) | 758 | static void __exit sgiseeq_exit(void) |
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c index e0a93005e6dc..bf218621db16 100644 --- a/drivers/net/sk98lin/skge.c +++ b/drivers/net/sk98lin/skge.c | |||
@@ -5123,7 +5123,12 @@ static int skge_resume(struct pci_dev *pdev) | |||
5123 | 5123 | ||
5124 | pci_set_power_state(pdev, PCI_D0); | 5124 | pci_set_power_state(pdev, PCI_D0); |
5125 | pci_restore_state(pdev); | 5125 | pci_restore_state(pdev); |
5126 | pci_enable_device(pdev); | 5126 | ret = pci_enable_device(pdev); |
5127 | if (ret) { | ||
5128 | printk(KERN_WARNING "sk98lin: unable to enable device %s " | ||
5129 | "in resume\n", dev->name); | ||
5130 | goto err_out; | ||
5131 | } | ||
5127 | pci_set_master(pdev); | 5132 | pci_set_master(pdev); |
5128 | if (pAC->GIni.GIMacsFound == 2) | 5133 | if (pAC->GIni.GIMacsFound == 2) |
5129 | ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev); | 5134 | ret = request_irq(dev->irq, SkGeIsr, IRQF_SHARED, "sk98lin", dev); |
@@ -5131,10 +5136,8 @@ static int skge_resume(struct pci_dev *pdev) | |||
5131 | ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev); | 5136 | ret = request_irq(dev->irq, SkGeIsrOnePort, IRQF_SHARED, "sk98lin", dev); |
5132 | if (ret) { | 5137 | if (ret) { |
5133 | printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq); | 5138 | printk(KERN_WARNING "sk98lin: unable to acquire IRQ %d\n", dev->irq); |
5134 | pAC->AllocFlag &= ~SK_ALLOC_IRQ; | 5139 | ret = -EBUSY; |
5135 | dev->irq = 0; | 5140 | goto err_out_disable_pdev; |
5136 | pci_disable_device(pdev); | ||
5137 | return -EBUSY; | ||
5138 | } | 5141 | } |
5139 | 5142 | ||
5140 | netif_device_attach(dev); | 5143 | netif_device_attach(dev); |
@@ -5151,6 +5154,13 @@ static int skge_resume(struct pci_dev *pdev) | |||
5151 | } | 5154 | } |
5152 | 5155 | ||
5153 | return 0; | 5156 | return 0; |
5157 | |||
5158 | err_out_disable_pdev: | ||
5159 | pci_disable_device(pdev); | ||
5160 | err_out: | ||
5161 | pAC->AllocFlag &= ~SK_ALLOC_IRQ; | ||
5162 | dev->irq = 0; | ||
5163 | return ret; | ||
5154 | } | 5164 | } |
5155 | #else | 5165 | #else |
5156 | #define skge_suspend NULL | 5166 | #define skge_suspend NULL |
diff --git a/drivers/net/skfp/h/lnkstat.h b/drivers/net/skfp/h/lnkstat.h deleted file mode 100644 index c73dcd96a40f..000000000000 --- a/drivers/net/skfp/h/lnkstat.h +++ /dev/null | |||
@@ -1,84 +0,0 @@ | |||
1 | /****************************************************************************** | ||
2 | * | ||
3 | * (C)Copyright 1998,1999 SysKonnect, | ||
4 | * a business unit of Schneider & Koch & Co. Datensysteme GmbH. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * The information in this file is provided "AS IS" without warranty. | ||
12 | * | ||
13 | ******************************************************************************/ | ||
14 | |||
15 | /* | ||
16 | * Definition of the Error Log Structure | ||
17 | * This structure will be copied into the Error Log buffer | ||
18 | * during the NDIS General Request ReadErrorLog by the MAC Driver | ||
19 | */ | ||
20 | |||
21 | struct s_error_log { | ||
22 | |||
23 | /* | ||
24 | * place holder for token ring adapter error log (zeros) | ||
25 | */ | ||
26 | u_char reserved_0 ; /* byte 0 inside Error Log */ | ||
27 | u_char reserved_1 ; /* byte 1 */ | ||
28 | u_char reserved_2 ; /* byte 2 */ | ||
29 | u_char reserved_3 ; /* byte 3 */ | ||
30 | u_char reserved_4 ; /* byte 4 */ | ||
31 | u_char reserved_5 ; /* byte 5 */ | ||
32 | u_char reserved_6 ; /* byte 6 */ | ||
33 | u_char reserved_7 ; /* byte 7 */ | ||
34 | u_char reserved_8 ; /* byte 8 */ | ||
35 | u_char reserved_9 ; /* byte 9 */ | ||
36 | u_char reserved_10 ; /* byte 10 */ | ||
37 | u_char reserved_11 ; /* byte 11 */ | ||
38 | u_char reserved_12 ; /* byte 12 */ | ||
39 | u_char reserved_13 ; /* byte 13 */ | ||
40 | |||
41 | /* | ||
42 | * FDDI link statistics | ||
43 | */ | ||
44 | /* | ||
45 | * smt error low | ||
46 | */ | ||
47 | #define SMT_ERL_AEB (1<<15) /* A elast. buffer */ | ||
48 | #define SMT_ERL_BLC (1<<14) /* B link error condition */ | ||
49 | #define SMT_ERL_ALC (1<<13) /* A link error condition */ | ||
50 | #define SMT_ERL_NCC (1<<12) /* not copied condition */ | ||
51 | #define SMT_ERL_FEC (1<<11) /* frame error condition */ | ||
52 | |||
53 | /* | ||
54 | * smt event low | ||
55 | */ | ||
56 | #define SMT_EVL_NCE (1<<5) | ||
57 | |||
58 | u_short smt_error_low ; /* byte 14/15 */ | ||
59 | u_short smt_error_high ; /* byte 16/17 */ | ||
60 | u_short smt_event_low ; /* byte 18/19 */ | ||
61 | u_short smt_event_high ; /* byte 20/21 */ | ||
62 | u_short connection_policy_violation ; /* byte 22/23 */ | ||
63 | u_short port_event ; /* byte 24/25 */ | ||
64 | u_short set_count_low ; /* byte 26/27 */ | ||
65 | u_short set_count_high ; /* byte 28/29 */ | ||
66 | u_short aci_id_code ; /* byte 30/31 */ | ||
67 | u_short purge_frame_counter ; /* byte 32/33 */ | ||
68 | |||
69 | /* | ||
70 | * CMT and RMT state machines | ||
71 | */ | ||
72 | u_short ecm_state ; /* byte 34/35 */ | ||
73 | u_short pcm_a_state ; /* byte 36/37 */ | ||
74 | u_short pcm_b_state ; /* byte 38/39 */ | ||
75 | u_short cfm_state ; /* byte 40/41 */ | ||
76 | u_short rmt_state ; /* byte 42/43 */ | ||
77 | |||
78 | u_short not_used[30] ; /* byte 44-103 */ | ||
79 | |||
80 | u_short ucode_version_level ; /* byte 104/105 */ | ||
81 | |||
82 | u_short not_used_1 ; /* byte 106/107 */ | ||
83 | u_short not_used_2 ; /* byte 108/109 */ | ||
84 | } ; | ||
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index f1a0e6c0fbdd..21afe108d3cb 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
@@ -42,7 +42,7 @@ | |||
42 | #include "skge.h" | 42 | #include "skge.h" |
43 | 43 | ||
44 | #define DRV_NAME "skge" | 44 | #define DRV_NAME "skge" |
45 | #define DRV_VERSION "1.10" | 45 | #define DRV_VERSION "1.11" |
46 | #define PFX DRV_NAME " " | 46 | #define PFX DRV_NAME " " |
47 | 47 | ||
48 | #define DEFAULT_TX_RING_SIZE 128 | 48 | #define DEFAULT_TX_RING_SIZE 128 |
@@ -2621,6 +2621,7 @@ static int skge_down(struct net_device *dev) | |||
2621 | 2621 | ||
2622 | static inline int skge_avail(const struct skge_ring *ring) | 2622 | static inline int skge_avail(const struct skge_ring *ring) |
2623 | { | 2623 | { |
2624 | smp_mb(); | ||
2624 | return ((ring->to_clean > ring->to_use) ? 0 : ring->count) | 2625 | return ((ring->to_clean > ring->to_use) ? 0 : ring->count) |
2625 | + (ring->to_clean - ring->to_use) - 1; | 2626 | + (ring->to_clean - ring->to_use) - 1; |
2626 | } | 2627 | } |
@@ -2709,6 +2710,8 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev) | |||
2709 | dev->name, e - skge->tx_ring.start, skb->len); | 2710 | dev->name, e - skge->tx_ring.start, skb->len); |
2710 | 2711 | ||
2711 | skge->tx_ring.to_use = e->next; | 2712 | skge->tx_ring.to_use = e->next; |
2713 | smp_wmb(); | ||
2714 | |||
2712 | if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) { | 2715 | if (skge_avail(&skge->tx_ring) <= TX_LOW_WATER) { |
2713 | pr_debug("%s: transmit queue full\n", dev->name); | 2716 | pr_debug("%s: transmit queue full\n", dev->name); |
2714 | netif_stop_queue(dev); | 2717 | netif_stop_queue(dev); |
@@ -2726,8 +2729,6 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e, | |||
2726 | { | 2729 | { |
2727 | struct pci_dev *pdev = skge->hw->pdev; | 2730 | struct pci_dev *pdev = skge->hw->pdev; |
2728 | 2731 | ||
2729 | BUG_ON(!e->skb); | ||
2730 | |||
2731 | /* skb header vs. fragment */ | 2732 | /* skb header vs. fragment */ |
2732 | if (control & BMU_STF) | 2733 | if (control & BMU_STF) |
2733 | pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr), | 2734 | pci_unmap_single(pdev, pci_unmap_addr(e, mapaddr), |
@@ -2745,7 +2746,6 @@ static void skge_tx_free(struct skge_port *skge, struct skge_element *e, | |||
2745 | 2746 | ||
2746 | dev_kfree_skb(e->skb); | 2747 | dev_kfree_skb(e->skb); |
2747 | } | 2748 | } |
2748 | e->skb = NULL; | ||
2749 | } | 2749 | } |
2750 | 2750 | ||
2751 | /* Free all buffers in transmit ring */ | 2751 | /* Free all buffers in transmit ring */ |
@@ -3017,21 +3017,29 @@ static void skge_tx_done(struct net_device *dev) | |||
3017 | 3017 | ||
3018 | skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); | 3018 | skge_write8(skge->hw, Q_ADDR(txqaddr[skge->port], Q_CSR), CSR_IRQ_CL_F); |
3019 | 3019 | ||
3020 | netif_tx_lock(dev); | ||
3021 | for (e = ring->to_clean; e != ring->to_use; e = e->next) { | 3020 | for (e = ring->to_clean; e != ring->to_use; e = e->next) { |
3022 | struct skge_tx_desc *td = e->desc; | 3021 | u32 control = ((const struct skge_tx_desc *) e->desc)->control; |
3023 | 3022 | ||
3024 | if (td->control & BMU_OWN) | 3023 | if (control & BMU_OWN) |
3025 | break; | 3024 | break; |
3026 | 3025 | ||
3027 | skge_tx_free(skge, e, td->control); | 3026 | skge_tx_free(skge, e, control); |
3028 | } | 3027 | } |
3029 | skge->tx_ring.to_clean = e; | 3028 | skge->tx_ring.to_clean = e; |
3030 | 3029 | ||
3031 | if (skge_avail(&skge->tx_ring) > TX_LOW_WATER) | 3030 | /* Can run lockless until we need to synchronize to restart queue. */ |
3032 | netif_wake_queue(dev); | 3031 | smp_mb(); |
3032 | |||
3033 | if (unlikely(netif_queue_stopped(dev) && | ||
3034 | skge_avail(&skge->tx_ring) > TX_LOW_WATER)) { | ||
3035 | netif_tx_lock(dev); | ||
3036 | if (unlikely(netif_queue_stopped(dev) && | ||
3037 | skge_avail(&skge->tx_ring) > TX_LOW_WATER)) { | ||
3038 | netif_wake_queue(dev); | ||
3033 | 3039 | ||
3034 | netif_tx_unlock(dev); | 3040 | } |
3041 | netif_tx_unlock(dev); | ||
3042 | } | ||
3035 | } | 3043 | } |
3036 | 3044 | ||
3037 | static int skge_poll(struct net_device *dev, int *budget) | 3045 | static int skge_poll(struct net_device *dev, int *budget) |
diff --git a/drivers/net/skge.h b/drivers/net/skge.h index 86467ae74d45..edd71468220c 100644 --- a/drivers/net/skge.h +++ b/drivers/net/skge.h | |||
@@ -232,7 +232,6 @@ enum { | |||
232 | IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */ | 232 | IS_R2_PAR_ERR = 1<<0, /* Queue R2 Parity Error */ |
233 | 233 | ||
234 | IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT | 234 | IS_ERR_MSK = IS_IRQ_MST_ERR | IS_IRQ_STAT |
235 | | IS_NO_STAT_M1 | IS_NO_STAT_M2 | ||
236 | | IS_RAM_RD_PAR | IS_RAM_WR_PAR | 235 | | IS_RAM_RD_PAR | IS_RAM_WR_PAR |
237 | | IS_M1_PAR_ERR | IS_M2_PAR_ERR | 236 | | IS_M1_PAR_ERR | IS_M2_PAR_ERR |
238 | | IS_R1_PAR_ERR | IS_R2_PAR_ERR, | 237 | | IS_R1_PAR_ERR | IS_R2_PAR_ERR, |
@@ -2447,15 +2446,15 @@ enum pause_status { | |||
2447 | 2446 | ||
2448 | 2447 | ||
2449 | struct skge_port { | 2448 | struct skge_port { |
2450 | u32 msg_enable; | ||
2451 | struct skge_hw *hw; | 2449 | struct skge_hw *hw; |
2452 | struct net_device *netdev; | 2450 | struct net_device *netdev; |
2453 | int port; | 2451 | int port; |
2452 | u32 msg_enable; | ||
2454 | 2453 | ||
2455 | struct skge_ring tx_ring; | 2454 | struct skge_ring tx_ring; |
2456 | struct skge_ring rx_ring; | ||
2457 | 2455 | ||
2458 | struct net_device_stats net_stats; | 2456 | struct skge_ring rx_ring ____cacheline_aligned_in_smp; |
2457 | unsigned int rx_buf_size; | ||
2459 | 2458 | ||
2460 | struct timer_list link_timer; | 2459 | struct timer_list link_timer; |
2461 | enum pause_control flow_control; | 2460 | enum pause_control flow_control; |
@@ -2471,7 +2470,8 @@ struct skge_port { | |||
2471 | void *mem; /* PCI memory for rings */ | 2470 | void *mem; /* PCI memory for rings */ |
2472 | dma_addr_t dma; | 2471 | dma_addr_t dma; |
2473 | unsigned long mem_size; | 2472 | unsigned long mem_size; |
2474 | unsigned int rx_buf_size; | 2473 | |
2474 | struct net_device_stats net_stats; | ||
2475 | }; | 2475 | }; |
2476 | 2476 | ||
2477 | 2477 | ||
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 8a2109a913b6..81f24847c963 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c | |||
@@ -499,7 +499,7 @@ static inline void smc911x_rcv(struct net_device *dev) | |||
499 | SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_)); | 499 | SMC_SET_RX_CFG(RX_CFG_RX_END_ALGN4_ | ((2<<8) & RX_CFG_RXDOFF_)); |
500 | SMC_PULL_DATA(data, pkt_len+2+3); | 500 | SMC_PULL_DATA(data, pkt_len+2+3); |
501 | 501 | ||
502 | DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name,); | 502 | DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name); |
503 | PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64); | 503 | PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64); |
504 | dev->last_rx = jiffies; | 504 | dev->last_rx = jiffies; |
505 | skb->protocol = eth_type_trans(skb, dev); | 505 | skb->protocol = eth_type_trans(skb, dev); |
diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index d7741e23f8de..f1e2dfc795a2 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c | |||
@@ -1,35 +1,34 @@ | |||
1 | /* tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux. | 1 | /* |
2 | * | 2 | * tc35815.c: A TOSHIBA TC35815CF PCI 10/100Mbps ethernet driver for linux. |
3 | * Copyright 2001 MontaVista Software Inc. | ||
4 | * Author: MontaVista Software, Inc. | ||
5 | * ahennessy@mvista.com | ||
6 | * | 3 | * |
7 | * Based on skelton.c by Donald Becker. | 4 | * Based on skelton.c by Donald Becker. |
8 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
9 | * | 5 | * |
10 | * This program is free software; you can redistribute it and/or modify it | 6 | * This driver is a replacement of older and less maintained version. |
11 | * under the terms of the GNU General Public License as published by the | 7 | * This is a header of the older version: |
12 | * Free Software Foundation; either version 2 of the License, or (at your | 8 | * -----<snip>----- |
13 | * option) any later version. | 9 | * Copyright 2001 MontaVista Software Inc. |
10 | * Author: MontaVista Software, Inc. | ||
11 | * ahennessy@mvista.com | ||
12 | * Copyright (C) 2000-2001 Toshiba Corporation | ||
13 | * static const char *version = | ||
14 | * "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n"; | ||
15 | * -----<snip>----- | ||
14 | * | 16 | * |
15 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED | 17 | * This file is subject to the terms and conditions of the GNU General Public |
16 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | 18 | * License. See the file "COPYING" in the main directory of this archive |
17 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN | 19 | * for more details. |
18 | * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
19 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
20 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF | ||
21 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | ||
22 | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
23 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
24 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
25 | * | 20 | * |
26 | * You should have received a copy of the GNU General Public License along | 21 | * (C) Copyright TOSHIBA CORPORATION 2004-2005 |
27 | * with this program; if not, write to the Free Software Foundation, Inc., | 22 | * All Rights Reserved. |
28 | * 675 Mass Ave, Cambridge, MA 02139, USA. | ||
29 | */ | 23 | */ |
30 | 24 | ||
31 | static const char *version = | 25 | #ifdef TC35815_NAPI |
32 | "tc35815.c:v0.00 26/07/2000 by Toshiba Corporation\n"; | 26 | #define DRV_VERSION "1.35-NAPI" |
27 | #else | ||
28 | #define DRV_VERSION "1.35" | ||
29 | #endif | ||
30 | static const char *version = "tc35815.c:v" DRV_VERSION "\n"; | ||
31 | #define MODNAME "tc35815" | ||
33 | 32 | ||
34 | #include <linux/module.h> | 33 | #include <linux/module.h> |
35 | #include <linux/kernel.h> | 34 | #include <linux/kernel.h> |
@@ -40,6 +39,7 @@ static const char *version = | |||
40 | #include <linux/in.h> | 39 | #include <linux/in.h> |
41 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
42 | #include <linux/string.h> | 41 | #include <linux/string.h> |
42 | #include <linux/spinlock.h> | ||
43 | #include <linux/errno.h> | 43 | #include <linux/errno.h> |
44 | #include <linux/init.h> | 44 | #include <linux/init.h> |
45 | #include <linux/netdevice.h> | 45 | #include <linux/netdevice.h> |
@@ -47,36 +47,47 @@ static const char *version = | |||
47 | #include <linux/skbuff.h> | 47 | #include <linux/skbuff.h> |
48 | #include <linux/delay.h> | 48 | #include <linux/delay.h> |
49 | #include <linux/pci.h> | 49 | #include <linux/pci.h> |
50 | #include <linux/proc_fs.h> | 50 | #include <linux/mii.h> |
51 | #include <linux/spinlock.h> | 51 | #include <linux/ethtool.h> |
52 | #include <linux/bitops.h> | ||
53 | |||
54 | #include <asm/system.h> | ||
55 | #include <asm/io.h> | 52 | #include <asm/io.h> |
56 | #include <asm/dma.h> | ||
57 | #include <asm/byteorder.h> | 53 | #include <asm/byteorder.h> |
58 | 54 | ||
59 | /* | ||
60 | * The name of the card. Is used for messages and in the requests for | ||
61 | * io regions, irqs and dma channels | ||
62 | */ | ||
63 | static const char* cardname = "TC35815CF"; | ||
64 | #define TC35815_PROC_ENTRY "net/tc35815" | ||
65 | |||
66 | #define TC35815_MODULE_NAME "TC35815CF" | ||
67 | #define TX_TIMEOUT (4*HZ) | ||
68 | |||
69 | /* First, a few definitions that the brave might change. */ | 55 | /* First, a few definitions that the brave might change. */ |
70 | 56 | ||
71 | /* use 0 for production, 1 for verification, >2 for debug */ | ||
72 | #ifndef TC35815_DEBUG | ||
73 | #define TC35815_DEBUG 1 | ||
74 | #endif | ||
75 | static unsigned int tc35815_debug = TC35815_DEBUG; | ||
76 | |||
77 | #define GATHER_TXINT /* On-Demand Tx Interrupt */ | 57 | #define GATHER_TXINT /* On-Demand Tx Interrupt */ |
58 | #define WORKAROUND_LOSTCAR | ||
59 | #define WORKAROUND_100HALF_PROMISC | ||
60 | /* #define TC35815_USE_PACKEDBUFFER */ | ||
61 | |||
62 | typedef enum { | ||
63 | TC35815CF = 0, | ||
64 | TC35815_NWU, | ||
65 | TC35815_TX4939, | ||
66 | } board_t; | ||
67 | |||
68 | /* indexed by board_t, above */ | ||
69 | static const struct { | ||
70 | const char *name; | ||
71 | } board_info[] __devinitdata = { | ||
72 | { "TOSHIBA TC35815CF 10/100BaseTX" }, | ||
73 | { "TOSHIBA TC35815 with Wake on LAN" }, | ||
74 | { "TOSHIBA TC35815/TX4939" }, | ||
75 | }; | ||
76 | |||
77 | static const struct pci_device_id tc35815_pci_tbl[] = { | ||
78 | {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF), .driver_data = TC35815CF }, | ||
79 | {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_NWU), .driver_data = TC35815_NWU }, | ||
80 | {PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939), .driver_data = TC35815_TX4939 }, | ||
81 | {0,} | ||
82 | }; | ||
83 | MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); | ||
78 | 84 | ||
79 | #define vtonocache(p) KSEG1ADDR(virt_to_phys(p)) | 85 | /* see MODULE_PARM_DESC */ |
86 | static struct tc35815_options { | ||
87 | int speed; | ||
88 | int duplex; | ||
89 | int doforce; | ||
90 | } options; | ||
80 | 91 | ||
81 | /* | 92 | /* |
82 | * Registers | 93 | * Registers |
@@ -119,6 +130,11 @@ struct tc35815_regs { | |||
119 | * Bit assignments | 130 | * Bit assignments |
120 | */ | 131 | */ |
121 | /* DMA_Ctl bit asign ------------------------------------------------------- */ | 132 | /* DMA_Ctl bit asign ------------------------------------------------------- */ |
133 | #define DMA_RxAlign 0x00c00000 /* 1:Reception Alignment */ | ||
134 | #define DMA_RxAlign_1 0x00400000 | ||
135 | #define DMA_RxAlign_2 0x00800000 | ||
136 | #define DMA_RxAlign_3 0x00c00000 | ||
137 | #define DMA_M66EnStat 0x00080000 /* 1:66MHz Enable State */ | ||
122 | #define DMA_IntMask 0x00040000 /* 1:Interupt mask */ | 138 | #define DMA_IntMask 0x00040000 /* 1:Interupt mask */ |
123 | #define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ | 139 | #define DMA_SWIntReq 0x00020000 /* 1:Software Interrupt request */ |
124 | #define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ | 140 | #define DMA_TxWakeUp 0x00010000 /* 1:Transmit Wake Up */ |
@@ -269,42 +285,6 @@ struct tc35815_regs { | |||
269 | #define MD_CA_Wr 0x00000400 /* 1:Write 0:Read */ | 285 | #define MD_CA_Wr 0x00000400 /* 1:Write 0:Read */ |
270 | 286 | ||
271 | 287 | ||
272 | /* MII register offsets */ | ||
273 | #define MII_CONTROL 0x0000 | ||
274 | #define MII_STATUS 0x0001 | ||
275 | #define MII_PHY_ID0 0x0002 | ||
276 | #define MII_PHY_ID1 0x0003 | ||
277 | #define MII_ANAR 0x0004 | ||
278 | #define MII_ANLPAR 0x0005 | ||
279 | #define MII_ANER 0x0006 | ||
280 | /* MII Control register bit definitions. */ | ||
281 | #define MIICNTL_FDX 0x0100 | ||
282 | #define MIICNTL_RST_AUTO 0x0200 | ||
283 | #define MIICNTL_ISOLATE 0x0400 | ||
284 | #define MIICNTL_PWRDWN 0x0800 | ||
285 | #define MIICNTL_AUTO 0x1000 | ||
286 | #define MIICNTL_SPEED 0x2000 | ||
287 | #define MIICNTL_LPBK 0x4000 | ||
288 | #define MIICNTL_RESET 0x8000 | ||
289 | /* MII Status register bit significance. */ | ||
290 | #define MIISTAT_EXT 0x0001 | ||
291 | #define MIISTAT_JAB 0x0002 | ||
292 | #define MIISTAT_LINK 0x0004 | ||
293 | #define MIISTAT_CAN_AUTO 0x0008 | ||
294 | #define MIISTAT_FAULT 0x0010 | ||
295 | #define MIISTAT_AUTO_DONE 0x0020 | ||
296 | #define MIISTAT_CAN_T 0x0800 | ||
297 | #define MIISTAT_CAN_T_FDX 0x1000 | ||
298 | #define MIISTAT_CAN_TX 0x2000 | ||
299 | #define MIISTAT_CAN_TX_FDX 0x4000 | ||
300 | #define MIISTAT_CAN_T4 0x8000 | ||
301 | /* MII Auto-Negotiation Expansion/RemoteEnd Register Bits */ | ||
302 | #define MII_AN_TX_FDX 0x0100 | ||
303 | #define MII_AN_TX_HDX 0x0080 | ||
304 | #define MII_AN_10_FDX 0x0040 | ||
305 | #define MII_AN_10_HDX 0x0020 | ||
306 | |||
307 | |||
308 | /* | 288 | /* |
309 | * Descriptors | 289 | * Descriptors |
310 | */ | 290 | */ |
@@ -352,32 +332,51 @@ struct BDesc { | |||
352 | 332 | ||
353 | #ifdef NO_CHECK_CARRIER | 333 | #ifdef NO_CHECK_CARRIER |
354 | #define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \ | 334 | #define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \ |
355 | Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \ | 335 | Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \ |
356 | Tx_En) /* maybe 0x7d01 */ | 336 | Tx_En) /* maybe 0x7b01 */ |
357 | #else | 337 | #else |
358 | #define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \ | 338 | #define TX_CTL_CMD (Tx_EnComp | Tx_EnTxPar | Tx_EnLateColl | \ |
359 | Tx_EnExColl | Tx_EnExDefer | Tx_EnUnder | \ | 339 | Tx_EnExColl | Tx_EnLCarr | Tx_EnExDefer | Tx_EnUnder | \ |
360 | Tx_En) /* maybe 0x7f01 */ | 340 | Tx_En) /* maybe 0x7b01 */ |
361 | #endif | 341 | #endif |
362 | #define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \ | 342 | #define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \ |
363 | | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */ | 343 | | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */ |
364 | |||
365 | #define INT_EN_CMD (Int_NRAbtEn | \ | 344 | #define INT_EN_CMD (Int_NRAbtEn | \ |
366 | Int_DParDEn | Int_DParErrEn | \ | 345 | Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \ |
367 | Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \ | 346 | Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \ |
368 | Int_STargAbtEn | \ | 347 | Int_STargAbtEn | \ |
369 | Int_BLExEn | Int_FDAExEn) /* maybe 0xb7f*/ | 348 | Int_BLExEn | Int_FDAExEn) /* maybe 0xb7f*/ |
349 | #define DMA_CTL_CMD DMA_BURST_SIZE | ||
350 | #define HAVE_DMA_RXALIGN(lp) likely((lp)->boardtype != TC35815CF) | ||
370 | 351 | ||
371 | /* Tuning parameters */ | 352 | /* Tuning parameters */ |
372 | #define DMA_BURST_SIZE 32 | 353 | #define DMA_BURST_SIZE 32 |
373 | #define TX_THRESHOLD 1024 | 354 | #define TX_THRESHOLD 1024 |
355 | #define TX_THRESHOLD_MAX 1536 /* used threshold with packet max byte for low pci transfer ability.*/ | ||
356 | #define TX_THRESHOLD_KEEP_LIMIT 10 /* setting threshold max value when overrun error occured this count. */ | ||
374 | 357 | ||
358 | /* 16 + RX_BUF_NUM * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*FD_PAGE_NUM */ | ||
359 | #ifdef TC35815_USE_PACKEDBUFFER | ||
375 | #define FD_PAGE_NUM 2 | 360 | #define FD_PAGE_NUM 2 |
376 | #define FD_PAGE_ORDER 1 | 361 | #define RX_BUF_NUM 8 /* >= 2 */ |
377 | /* 16 + RX_BUF_PAGES * 8 + RX_FD_NUM * 16 + TX_FD_NUM * 32 <= PAGE_SIZE*2 */ | ||
378 | #define RX_BUF_PAGES 8 /* >= 2 */ | ||
379 | #define RX_FD_NUM 250 /* >= 32 */ | 362 | #define RX_FD_NUM 250 /* >= 32 */ |
380 | #define TX_FD_NUM 128 | 363 | #define TX_FD_NUM 128 |
364 | #define RX_BUF_SIZE PAGE_SIZE | ||
365 | #else /* TC35815_USE_PACKEDBUFFER */ | ||
366 | #define FD_PAGE_NUM 4 | ||
367 | #define RX_BUF_NUM 128 /* < 256 */ | ||
368 | #define RX_FD_NUM 256 /* >= 32 */ | ||
369 | #define TX_FD_NUM 128 | ||
370 | #if RX_CTL_CMD & Rx_LongEn | ||
371 | #define RX_BUF_SIZE PAGE_SIZE | ||
372 | #elif RX_CTL_CMD & Rx_StripCRC | ||
373 | #define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */ | ||
374 | #else | ||
375 | #define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */ | ||
376 | #endif | ||
377 | #endif /* TC35815_USE_PACKEDBUFFER */ | ||
378 | #define RX_FD_RESERVE (2 / 2) /* max 2 BD per RxFD */ | ||
379 | #define NAPI_WEIGHT 16 | ||
381 | 380 | ||
382 | struct TxFD { | 381 | struct TxFD { |
383 | struct FDesc fd; | 382 | struct FDesc fd; |
@@ -392,18 +391,27 @@ struct RxFD { | |||
392 | 391 | ||
393 | struct FrFD { | 392 | struct FrFD { |
394 | struct FDesc fd; | 393 | struct FDesc fd; |
395 | struct BDesc bd[RX_BUF_PAGES]; | 394 | struct BDesc bd[RX_BUF_NUM]; |
396 | }; | 395 | }; |
397 | 396 | ||
398 | 397 | ||
399 | extern unsigned long tc_readl(volatile __u32 *addr); | 398 | #define tc_readl(addr) readl(addr) |
400 | extern void tc_writel(unsigned long data, volatile __u32 *addr); | 399 | #define tc_writel(d, addr) writel(d, addr) |
400 | |||
401 | #define TC35815_TX_TIMEOUT msecs_to_jiffies(400) | ||
401 | 402 | ||
402 | dma_addr_t priv_dma_handle; | 403 | /* Timer state engine. */ |
404 | enum tc35815_timer_state { | ||
405 | arbwait = 0, /* Waiting for auto negotiation to complete. */ | ||
406 | lupwait = 1, /* Auto-neg complete, awaiting link-up status. */ | ||
407 | ltrywait = 2, /* Forcing try of all modes, from fastest to slowest. */ | ||
408 | asleep = 3, /* Time inactive. */ | ||
409 | lcheck = 4, /* Check link status. */ | ||
410 | }; | ||
403 | 411 | ||
404 | /* Information that need to be kept for each board. */ | 412 | /* Information that need to be kept for each board. */ |
405 | struct tc35815_local { | 413 | struct tc35815_local { |
406 | struct net_device *next_module; | 414 | struct pci_dev *pci_dev; |
407 | 415 | ||
408 | /* statistics */ | 416 | /* statistics */ |
409 | struct net_device_stats stats; | 417 | struct net_device_stats stats; |
@@ -411,216 +419,372 @@ struct tc35815_local { | |||
411 | int max_tx_qlen; | 419 | int max_tx_qlen; |
412 | int tx_ints; | 420 | int tx_ints; |
413 | int rx_ints; | 421 | int rx_ints; |
422 | int tx_underrun; | ||
414 | } lstats; | 423 | } lstats; |
415 | 424 | ||
416 | int tbusy; | 425 | /* Tx control lock. This protects the transmit buffer ring |
417 | int option; | 426 | * state along with the "tx full" state of the driver. This |
418 | #define TC35815_OPT_AUTO 0x00 | 427 | * means all netif_queue flow control actions are protected |
419 | #define TC35815_OPT_10M 0x01 | 428 | * by this lock as well. |
420 | #define TC35815_OPT_100M 0x02 | 429 | */ |
421 | #define TC35815_OPT_FULLDUP 0x04 | 430 | spinlock_t lock; |
422 | int linkspeed; /* 10 or 100 */ | 431 | |
432 | int phy_addr; | ||
423 | int fullduplex; | 433 | int fullduplex; |
434 | unsigned short saved_lpa; | ||
435 | struct timer_list timer; | ||
436 | enum tc35815_timer_state timer_state; /* State of auto-neg timer. */ | ||
437 | unsigned int timer_ticks; /* Number of clicks at each state */ | ||
424 | 438 | ||
425 | /* | 439 | /* |
426 | * Transmitting: Batch Mode. | 440 | * Transmitting: Batch Mode. |
427 | * 1 BD in 1 TxFD. | 441 | * 1 BD in 1 TxFD. |
428 | * Receiving: Packing Mode. | 442 | * Receiving: Packing Mode. (TC35815_USE_PACKEDBUFFER) |
429 | * 1 circular FD for Free Buffer List. | 443 | * 1 circular FD for Free Buffer List. |
430 | * RX_BUG_PAGES BD in Free Buffer FD. | 444 | * RX_BUF_NUM BD in Free Buffer FD. |
431 | * One Free Buffer BD has PAGE_SIZE data buffer. | 445 | * One Free Buffer BD has PAGE_SIZE data buffer. |
446 | * Or Non-Packing Mode. | ||
447 | * 1 circular FD for Free Buffer List. | ||
448 | * RX_BUF_NUM BD in Free Buffer FD. | ||
449 | * One Free Buffer BD has ETH_FRAME_LEN data buffer. | ||
432 | */ | 450 | */ |
433 | struct pci_dev *pdev; | 451 | void * fd_buf; /* for TxFD, RxFD, FrFD */ |
434 | dma_addr_t fd_buf_dma_handle; | 452 | dma_addr_t fd_buf_dma; |
435 | void * fd_buf; /* for TxFD, TxFD, FrFD */ | ||
436 | struct TxFD *tfd_base; | 453 | struct TxFD *tfd_base; |
437 | int tfd_start; | 454 | unsigned int tfd_start; |
438 | int tfd_end; | 455 | unsigned int tfd_end; |
439 | struct RxFD *rfd_base; | 456 | struct RxFD *rfd_base; |
440 | struct RxFD *rfd_limit; | 457 | struct RxFD *rfd_limit; |
441 | struct RxFD *rfd_cur; | 458 | struct RxFD *rfd_cur; |
442 | struct FrFD *fbl_ptr; | 459 | struct FrFD *fbl_ptr; |
460 | #ifdef TC35815_USE_PACKEDBUFFER | ||
443 | unsigned char fbl_curid; | 461 | unsigned char fbl_curid; |
444 | dma_addr_t data_buf_dma_handle[RX_BUF_PAGES]; | 462 | void * data_buf[RX_BUF_NUM]; /* packing */ |
445 | void * data_buf[RX_BUF_PAGES]; /* packing */ | 463 | dma_addr_t data_buf_dma[RX_BUF_NUM]; |
446 | spinlock_t lock; | 464 | struct { |
465 | struct sk_buff *skb; | ||
466 | dma_addr_t skb_dma; | ||
467 | } tx_skbs[TX_FD_NUM]; | ||
468 | #else | ||
469 | unsigned int fbl_count; | ||
470 | struct { | ||
471 | struct sk_buff *skb; | ||
472 | dma_addr_t skb_dma; | ||
473 | } tx_skbs[TX_FD_NUM], rx_skbs[RX_BUF_NUM]; | ||
474 | #endif | ||
475 | struct mii_if_info mii; | ||
476 | unsigned short mii_id[2]; | ||
477 | u32 msg_enable; | ||
478 | board_t boardtype; | ||
447 | }; | 479 | }; |
448 | 480 | ||
449 | /* Index to functions, as function prototypes. */ | 481 | static inline dma_addr_t fd_virt_to_bus(struct tc35815_local *lp, void *virt) |
482 | { | ||
483 | return lp->fd_buf_dma + ((u8 *)virt - (u8 *)lp->fd_buf); | ||
484 | } | ||
485 | #ifdef DEBUG | ||
486 | static inline void *fd_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus) | ||
487 | { | ||
488 | return (void *)((u8 *)lp->fd_buf + (bus - lp->fd_buf_dma)); | ||
489 | } | ||
490 | #endif | ||
491 | #ifdef TC35815_USE_PACKEDBUFFER | ||
492 | static inline void *rxbuf_bus_to_virt(struct tc35815_local *lp, dma_addr_t bus) | ||
493 | { | ||
494 | int i; | ||
495 | for (i = 0; i < RX_BUF_NUM; i++) { | ||
496 | if (bus >= lp->data_buf_dma[i] && | ||
497 | bus < lp->data_buf_dma[i] + PAGE_SIZE) | ||
498 | return (void *)((u8 *)lp->data_buf[i] + | ||
499 | (bus - lp->data_buf_dma[i])); | ||
500 | } | ||
501 | return NULL; | ||
502 | } | ||
450 | 503 | ||
451 | static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq); | 504 | #define TC35815_DMA_SYNC_ONDEMAND |
505 | static void* alloc_rxbuf_page(struct pci_dev *hwdev, dma_addr_t *dma_handle) | ||
506 | { | ||
507 | #ifdef TC35815_DMA_SYNC_ONDEMAND | ||
508 | void *buf; | ||
509 | /* pci_map + pci_dma_sync will be more effective than | ||
510 | * pci_alloc_consistent on some archs. */ | ||
511 | if ((buf = (void *)__get_free_page(GFP_ATOMIC)) == NULL) | ||
512 | return NULL; | ||
513 | *dma_handle = pci_map_single(hwdev, buf, PAGE_SIZE, | ||
514 | PCI_DMA_FROMDEVICE); | ||
515 | if (pci_dma_mapping_error(*dma_handle)) { | ||
516 | free_page((unsigned long)buf); | ||
517 | return NULL; | ||
518 | } | ||
519 | return buf; | ||
520 | #else | ||
521 | return pci_alloc_consistent(hwdev, PAGE_SIZE, dma_handle); | ||
522 | #endif | ||
523 | } | ||
524 | |||
525 | static void free_rxbuf_page(struct pci_dev *hwdev, void *buf, dma_addr_t dma_handle) | ||
526 | { | ||
527 | #ifdef TC35815_DMA_SYNC_ONDEMAND | ||
528 | pci_unmap_single(hwdev, dma_handle, PAGE_SIZE, PCI_DMA_FROMDEVICE); | ||
529 | free_page((unsigned long)buf); | ||
530 | #else | ||
531 | pci_free_consistent(hwdev, PAGE_SIZE, buf, dma_handle); | ||
532 | #endif | ||
533 | } | ||
534 | #else /* TC35815_USE_PACKEDBUFFER */ | ||
535 | static struct sk_buff *alloc_rxbuf_skb(struct net_device *dev, | ||
536 | struct pci_dev *hwdev, | ||
537 | dma_addr_t *dma_handle) | ||
538 | { | ||
539 | struct sk_buff *skb; | ||
540 | skb = dev_alloc_skb(RX_BUF_SIZE); | ||
541 | if (!skb) | ||
542 | return NULL; | ||
543 | skb->dev = dev; | ||
544 | *dma_handle = pci_map_single(hwdev, skb->data, RX_BUF_SIZE, | ||
545 | PCI_DMA_FROMDEVICE); | ||
546 | if (pci_dma_mapping_error(*dma_handle)) { | ||
547 | dev_kfree_skb_any(skb); | ||
548 | return NULL; | ||
549 | } | ||
550 | skb_reserve(skb, 2); /* make IP header 4byte aligned */ | ||
551 | return skb; | ||
552 | } | ||
553 | |||
554 | static void free_rxbuf_skb(struct pci_dev *hwdev, struct sk_buff *skb, dma_addr_t dma_handle) | ||
555 | { | ||
556 | pci_unmap_single(hwdev, dma_handle, RX_BUF_SIZE, | ||
557 | PCI_DMA_FROMDEVICE); | ||
558 | dev_kfree_skb_any(skb); | ||
559 | } | ||
560 | #endif /* TC35815_USE_PACKEDBUFFER */ | ||
561 | |||
562 | /* Index to functions, as function prototypes. */ | ||
452 | 563 | ||
453 | static int tc35815_open(struct net_device *dev); | 564 | static int tc35815_open(struct net_device *dev); |
454 | static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); | 565 | static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev); |
455 | static void tc35815_tx_timeout(struct net_device *dev); | 566 | static irqreturn_t tc35815_interrupt(int irq, void *dev_id); |
456 | static irqreturn_t tc35815_interrupt(int irq, void *dev_id); | 567 | #ifdef TC35815_NAPI |
568 | static int tc35815_rx(struct net_device *dev, int limit); | ||
569 | static int tc35815_poll(struct net_device *dev, int *budget); | ||
570 | #else | ||
457 | static void tc35815_rx(struct net_device *dev); | 571 | static void tc35815_rx(struct net_device *dev); |
572 | #endif | ||
458 | static void tc35815_txdone(struct net_device *dev); | 573 | static void tc35815_txdone(struct net_device *dev); |
459 | static int tc35815_close(struct net_device *dev); | 574 | static int tc35815_close(struct net_device *dev); |
460 | static struct net_device_stats *tc35815_get_stats(struct net_device *dev); | 575 | static struct net_device_stats *tc35815_get_stats(struct net_device *dev); |
461 | static void tc35815_set_multicast_list(struct net_device *dev); | 576 | static void tc35815_set_multicast_list(struct net_device *dev); |
577 | static void tc35815_tx_timeout(struct net_device *dev); | ||
578 | static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); | ||
579 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
580 | static void tc35815_poll_controller(struct net_device *dev); | ||
581 | #endif | ||
582 | static const struct ethtool_ops tc35815_ethtool_ops; | ||
462 | 583 | ||
584 | /* Example routines you must write ;->. */ | ||
463 | static void tc35815_chip_reset(struct net_device *dev); | 585 | static void tc35815_chip_reset(struct net_device *dev); |
464 | static void tc35815_chip_init(struct net_device *dev); | 586 | static void tc35815_chip_init(struct net_device *dev); |
587 | static void tc35815_find_phy(struct net_device *dev); | ||
465 | static void tc35815_phy_chip_init(struct net_device *dev); | 588 | static void tc35815_phy_chip_init(struct net_device *dev); |
466 | 589 | ||
467 | /* A list of all installed tc35815 devices. */ | 590 | #ifdef DEBUG |
468 | static struct net_device *root_tc35815_dev = NULL; | 591 | static void panic_queues(struct net_device *dev); |
592 | #endif | ||
469 | 593 | ||
470 | /* | 594 | static void tc35815_timer(unsigned long data); |
471 | * PCI device identifiers for "new style" Linux PCI Device Drivers | 595 | static void tc35815_start_auto_negotiation(struct net_device *dev, |
472 | */ | 596 | struct ethtool_cmd *ep); |
473 | static struct pci_device_id tc35815_pci_tbl[] = { | 597 | static int tc_mdio_read(struct net_device *dev, int phy_id, int location); |
474 | { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC35815CF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | 598 | static void tc_mdio_write(struct net_device *dev, int phy_id, int location, |
475 | { 0, } | 599 | int val); |
476 | }; | ||
477 | 600 | ||
478 | MODULE_DEVICE_TABLE (pci, tc35815_pci_tbl); | 601 | static void __devinit tc35815_init_dev_addr (struct net_device *dev) |
602 | { | ||
603 | struct tc35815_regs __iomem *tr = | ||
604 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
605 | int i; | ||
479 | 606 | ||
480 | int | 607 | /* dev_addr will be overwritten on NETDEV_REGISTER event */ |
481 | tc35815_probe(struct pci_dev *pdev, | 608 | while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) |
482 | const struct pci_device_id *ent) | 609 | ; |
610 | for (i = 0; i < 6; i += 2) { | ||
611 | unsigned short data; | ||
612 | tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); | ||
613 | while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) | ||
614 | ; | ||
615 | data = tc_readl(&tr->PROM_Data); | ||
616 | dev->dev_addr[i] = data & 0xff; | ||
617 | dev->dev_addr[i+1] = data >> 8; | ||
618 | } | ||
619 | } | ||
620 | |||
621 | static int __devinit tc35815_init_one (struct pci_dev *pdev, | ||
622 | const struct pci_device_id *ent) | ||
483 | { | 623 | { |
484 | int err = 0; | 624 | void __iomem *ioaddr = NULL; |
485 | int ret; | 625 | struct net_device *dev; |
486 | unsigned long pci_memaddr; | 626 | struct tc35815_local *lp; |
487 | unsigned int pci_irq_line; | 627 | int rc; |
628 | unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; | ||
629 | |||
630 | static int printed_version; | ||
631 | if (!printed_version++) { | ||
632 | printk(version); | ||
633 | dev_printk(KERN_DEBUG, &pdev->dev, | ||
634 | "speed:%d duplex:%d doforce:%d\n", | ||
635 | options.speed, options.duplex, options.doforce); | ||
636 | } | ||
488 | 637 | ||
489 | printk(KERN_INFO "tc35815_probe: found device %#08x.%#08x\n", ent->vendor, ent->device); | 638 | if (!pdev->irq) { |
639 | dev_warn(&pdev->dev, "no IRQ assigned.\n"); | ||
640 | return -ENODEV; | ||
641 | } | ||
490 | 642 | ||
491 | err = pci_enable_device(pdev); | 643 | /* dev zeroed in alloc_etherdev */ |
492 | if (err) | 644 | dev = alloc_etherdev (sizeof (*lp)); |
493 | return err; | 645 | if (dev == NULL) { |
646 | dev_err(&pdev->dev, "unable to alloc new ethernet\n"); | ||
647 | return -ENOMEM; | ||
648 | } | ||
649 | SET_MODULE_OWNER(dev); | ||
650 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
651 | lp = dev->priv; | ||
652 | |||
653 | /* enable device (incl. PCI PM wakeup), and bus-mastering */ | ||
654 | rc = pci_enable_device (pdev); | ||
655 | if (rc) | ||
656 | goto err_out; | ||
494 | 657 | ||
495 | pci_memaddr = pci_resource_start (pdev, 1); | 658 | mmio_start = pci_resource_start (pdev, 1); |
659 | mmio_end = pci_resource_end (pdev, 1); | ||
660 | mmio_flags = pci_resource_flags (pdev, 1); | ||
661 | mmio_len = pci_resource_len (pdev, 1); | ||
496 | 662 | ||
497 | printk(KERN_INFO " pci_memaddr=%#08lx resource_flags=%#08lx\n", pci_memaddr, pci_resource_flags (pdev, 0)); | 663 | /* set this immediately, we need to know before |
664 | * we talk to the chip directly */ | ||
498 | 665 | ||
499 | if (!pci_memaddr) { | 666 | /* make sure PCI base addr 1 is MMIO */ |
500 | printk(KERN_WARNING "no PCI MEM resources, aborting\n"); | 667 | if (!(mmio_flags & IORESOURCE_MEM)) { |
501 | ret = -ENODEV; | 668 | dev_err(&pdev->dev, "region #1 not an MMIO resource, aborting\n"); |
669 | rc = -ENODEV; | ||
502 | goto err_out; | 670 | goto err_out; |
503 | } | 671 | } |
504 | pci_irq_line = pdev->irq; | 672 | |
505 | /* irq disabled. */ | 673 | /* check for weird/broken PCI region reporting */ |
506 | if (pci_irq_line == 0) { | 674 | if ((mmio_len < sizeof(struct tc35815_regs))) { |
507 | printk(KERN_WARNING "no PCI irq, aborting\n"); | 675 | dev_err(&pdev->dev, "Invalid PCI region size(s), aborting\n"); |
508 | ret = -ENODEV; | 676 | rc = -ENODEV; |
509 | goto err_out; | 677 | goto err_out; |
510 | } | 678 | } |
511 | 679 | ||
512 | ret = tc35815_probe1(pdev, pci_memaddr, pci_irq_line); | 680 | rc = pci_request_regions (pdev, MODNAME); |
513 | if (ret) | 681 | if (rc) |
514 | goto err_out; | 682 | goto err_out; |
515 | 683 | ||
516 | pci_set_master(pdev); | 684 | pci_set_master (pdev); |
517 | |||
518 | return 0; | ||
519 | 685 | ||
520 | err_out: | 686 | /* ioremap MMIO region */ |
521 | pci_disable_device(pdev); | 687 | ioaddr = ioremap (mmio_start, mmio_len); |
522 | return ret; | 688 | if (ioaddr == NULL) { |
523 | } | 689 | dev_err(&pdev->dev, "cannot remap MMIO, aborting\n"); |
690 | rc = -EIO; | ||
691 | goto err_out_free_res; | ||
692 | } | ||
524 | 693 | ||
525 | static int __devinit tc35815_probe1(struct pci_dev *pdev, unsigned int base_addr, unsigned int irq) | 694 | /* Initialize the device structure. */ |
526 | { | 695 | dev->open = tc35815_open; |
527 | static unsigned version_printed = 0; | 696 | dev->hard_start_xmit = tc35815_send_packet; |
528 | int i, ret; | 697 | dev->stop = tc35815_close; |
529 | struct tc35815_local *lp; | 698 | dev->get_stats = tc35815_get_stats; |
530 | struct tc35815_regs *tr; | 699 | dev->set_multicast_list = tc35815_set_multicast_list; |
531 | struct net_device *dev; | 700 | dev->do_ioctl = tc35815_ioctl; |
701 | dev->ethtool_ops = &tc35815_ethtool_ops; | ||
702 | dev->tx_timeout = tc35815_tx_timeout; | ||
703 | dev->watchdog_timeo = TC35815_TX_TIMEOUT; | ||
704 | #ifdef TC35815_NAPI | ||
705 | dev->poll = tc35815_poll; | ||
706 | dev->weight = NAPI_WEIGHT; | ||
707 | #endif | ||
708 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
709 | dev->poll_controller = tc35815_poll_controller; | ||
710 | #endif | ||
532 | 711 | ||
533 | /* Allocate a new 'dev' if needed. */ | 712 | dev->irq = pdev->irq; |
534 | dev = alloc_etherdev(sizeof(struct tc35815_local)); | 713 | dev->base_addr = (unsigned long) ioaddr; |
535 | if (dev == NULL) | ||
536 | return -ENOMEM; | ||
537 | 714 | ||
538 | /* | 715 | /* dev->priv/lp zeroed and aligned in alloc_etherdev */ |
539 | * alloc_etherdev allocs and zeros dev->priv | ||
540 | */ | ||
541 | lp = dev->priv; | 716 | lp = dev->priv; |
717 | spin_lock_init(&lp->lock); | ||
718 | lp->pci_dev = pdev; | ||
719 | lp->boardtype = ent->driver_data; | ||
542 | 720 | ||
543 | if (tc35815_debug && version_printed++ == 0) | 721 | lp->msg_enable = NETIF_MSG_TX_ERR | NETIF_MSG_HW | NETIF_MSG_DRV | NETIF_MSG_LINK; |
544 | printk(KERN_DEBUG "%s", version); | 722 | pci_set_drvdata(pdev, dev); |
545 | |||
546 | /* Fill in the 'dev' fields. */ | ||
547 | dev->irq = irq; | ||
548 | dev->base_addr = (unsigned long)ioremap(base_addr, | ||
549 | sizeof(struct tc35815_regs)); | ||
550 | if (!dev->base_addr) { | ||
551 | ret = -ENOMEM; | ||
552 | goto err_out; | ||
553 | } | ||
554 | tr = (struct tc35815_regs*)dev->base_addr; | ||
555 | 723 | ||
724 | /* Soft reset the chip. */ | ||
556 | tc35815_chip_reset(dev); | 725 | tc35815_chip_reset(dev); |
557 | 726 | ||
558 | /* Retrieve and print the ethernet address. */ | 727 | /* Retrieve the ethernet address. */ |
559 | while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) | 728 | tc35815_init_dev_addr(dev); |
560 | ; | 729 | |
561 | for (i = 0; i < 6; i += 2) { | 730 | rc = register_netdev (dev); |
562 | unsigned short data; | 731 | if (rc) |
563 | tc_writel(PROM_Busy | PROM_Read | (i / 2 + 2), &tr->PROM_Ctl); | 732 | goto err_out_unmap; |
564 | while (tc_readl(&tr->PROM_Ctl) & PROM_Busy) | 733 | |
565 | ; | 734 | memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); |
566 | data = tc_readl(&tr->PROM_Data); | 735 | printk(KERN_INFO "%s: %s at 0x%lx, " |
567 | dev->dev_addr[i] = data & 0xff; | 736 | "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x, " |
568 | dev->dev_addr[i+1] = data >> 8; | 737 | "IRQ %d\n", |
569 | } | 738 | dev->name, |
739 | board_info[ent->driver_data].name, | ||
740 | dev->base_addr, | ||
741 | dev->dev_addr[0], dev->dev_addr[1], | ||
742 | dev->dev_addr[2], dev->dev_addr[3], | ||
743 | dev->dev_addr[4], dev->dev_addr[5], | ||
744 | dev->irq); | ||
745 | |||
746 | setup_timer(&lp->timer, tc35815_timer, (unsigned long) dev); | ||
747 | lp->mii.dev = dev; | ||
748 | lp->mii.mdio_read = tc_mdio_read; | ||
749 | lp->mii.mdio_write = tc_mdio_write; | ||
750 | lp->mii.phy_id_mask = 0x1f; | ||
751 | lp->mii.reg_num_mask = 0x1f; | ||
752 | tc35815_find_phy(dev); | ||
753 | lp->mii.phy_id = lp->phy_addr; | ||
754 | lp->mii.full_duplex = 0; | ||
755 | lp->mii.force_media = 0; | ||
570 | 756 | ||
571 | /* Initialize the device structure. */ | 757 | return 0; |
572 | lp->pdev = pdev; | ||
573 | lp->next_module = root_tc35815_dev; | ||
574 | root_tc35815_dev = dev; | ||
575 | 758 | ||
576 | spin_lock_init(&lp->lock); | 759 | err_out_unmap: |
760 | iounmap(ioaddr); | ||
761 | err_out_free_res: | ||
762 | pci_release_regions (pdev); | ||
763 | err_out: | ||
764 | free_netdev (dev); | ||
765 | return rc; | ||
766 | } | ||
577 | 767 | ||
578 | if (dev->mem_start > 0) { | ||
579 | lp->option = dev->mem_start; | ||
580 | if ((lp->option & TC35815_OPT_10M) && | ||
581 | (lp->option & TC35815_OPT_100M)) { | ||
582 | /* if both speed speficied, auto select. */ | ||
583 | lp->option &= ~(TC35815_OPT_10M | TC35815_OPT_100M); | ||
584 | } | ||
585 | } | ||
586 | //XXX fixme | ||
587 | lp->option |= TC35815_OPT_10M; | ||
588 | 768 | ||
589 | /* do auto negotiation */ | 769 | static void __devexit tc35815_remove_one (struct pci_dev *pdev) |
590 | tc35815_phy_chip_init(dev); | 770 | { |
771 | struct net_device *dev = pci_get_drvdata (pdev); | ||
772 | unsigned long mmio_addr; | ||
591 | 773 | ||
592 | dev->open = tc35815_open; | 774 | mmio_addr = dev->base_addr; |
593 | dev->stop = tc35815_close; | ||
594 | dev->tx_timeout = tc35815_tx_timeout; | ||
595 | dev->watchdog_timeo = TX_TIMEOUT; | ||
596 | dev->hard_start_xmit = tc35815_send_packet; | ||
597 | dev->get_stats = tc35815_get_stats; | ||
598 | dev->set_multicast_list = tc35815_set_multicast_list; | ||
599 | SET_MODULE_OWNER(dev); | ||
600 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
601 | 775 | ||
602 | ret = register_netdev(dev); | 776 | unregister_netdev (dev); |
603 | if (ret) | ||
604 | goto err_out_iounmap; | ||
605 | 777 | ||
606 | printk(KERN_INFO "%s: %s found at %#x, irq %d, MAC", | 778 | if (mmio_addr) { |
607 | dev->name, cardname, base_addr, irq); | 779 | iounmap ((void __iomem *)mmio_addr); |
608 | for (i = 0; i < 6; i++) | 780 | pci_release_regions (pdev); |
609 | printk(" %2.2x", dev->dev_addr[i]); | 781 | } |
610 | printk("\n"); | ||
611 | printk(KERN_INFO "%s: linkspeed %dMbps, %s Duplex\n", | ||
612 | dev->name, lp->linkspeed, lp->fullduplex ? "Full" : "Half"); | ||
613 | 782 | ||
614 | return 0; | 783 | free_netdev (dev); |
615 | 784 | ||
616 | err_out_iounmap: | 785 | pci_set_drvdata (pdev, NULL); |
617 | iounmap((void *) dev->base_addr); | ||
618 | err_out: | ||
619 | free_netdev(dev); | ||
620 | return ret; | ||
621 | } | 786 | } |
622 | 787 | ||
623 | |||
624 | static int | 788 | static int |
625 | tc35815_init_queues(struct net_device *dev) | 789 | tc35815_init_queues(struct net_device *dev) |
626 | { | 790 | { |
@@ -629,44 +793,64 @@ tc35815_init_queues(struct net_device *dev) | |||
629 | unsigned long fd_addr; | 793 | unsigned long fd_addr; |
630 | 794 | ||
631 | if (!lp->fd_buf) { | 795 | if (!lp->fd_buf) { |
632 | if (sizeof(struct FDesc) + | 796 | BUG_ON(sizeof(struct FDesc) + |
633 | sizeof(struct BDesc) * RX_BUF_PAGES + | 797 | sizeof(struct BDesc) * RX_BUF_NUM + |
634 | sizeof(struct FDesc) * RX_FD_NUM + | 798 | sizeof(struct FDesc) * RX_FD_NUM + |
635 | sizeof(struct TxFD) * TX_FD_NUM > PAGE_SIZE * FD_PAGE_NUM) { | 799 | sizeof(struct TxFD) * TX_FD_NUM > |
636 | printk(KERN_WARNING "%s: Invalid Queue Size.\n", dev->name); | 800 | PAGE_SIZE * FD_PAGE_NUM); |
637 | return -ENOMEM; | ||
638 | } | ||
639 | 801 | ||
640 | if ((lp->fd_buf = (void *)__get_free_pages(GFP_KERNEL, FD_PAGE_ORDER)) == 0) | 802 | if ((lp->fd_buf = pci_alloc_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, &lp->fd_buf_dma)) == 0) |
641 | return -ENOMEM; | 803 | return -ENOMEM; |
642 | for (i = 0; i < RX_BUF_PAGES; i++) { | 804 | for (i = 0; i < RX_BUF_NUM; i++) { |
643 | if ((lp->data_buf[i] = (void *)get_zeroed_page(GFP_KERNEL)) == 0) { | 805 | #ifdef TC35815_USE_PACKEDBUFFER |
806 | if ((lp->data_buf[i] = alloc_rxbuf_page(lp->pci_dev, &lp->data_buf_dma[i])) == NULL) { | ||
644 | while (--i >= 0) { | 807 | while (--i >= 0) { |
645 | free_page((unsigned long)lp->data_buf[i]); | 808 | free_rxbuf_page(lp->pci_dev, |
646 | lp->data_buf[i] = 0; | 809 | lp->data_buf[i], |
810 | lp->data_buf_dma[i]); | ||
811 | lp->data_buf[i] = NULL; | ||
647 | } | 812 | } |
648 | free_page((unsigned long)lp->fd_buf); | 813 | pci_free_consistent(lp->pci_dev, |
649 | lp->fd_buf = 0; | 814 | PAGE_SIZE * FD_PAGE_NUM, |
815 | lp->fd_buf, | ||
816 | lp->fd_buf_dma); | ||
817 | lp->fd_buf = NULL; | ||
818 | return -ENOMEM; | ||
819 | } | ||
820 | #else | ||
821 | lp->rx_skbs[i].skb = | ||
822 | alloc_rxbuf_skb(dev, lp->pci_dev, | ||
823 | &lp->rx_skbs[i].skb_dma); | ||
824 | if (!lp->rx_skbs[i].skb) { | ||
825 | while (--i >= 0) { | ||
826 | free_rxbuf_skb(lp->pci_dev, | ||
827 | lp->rx_skbs[i].skb, | ||
828 | lp->rx_skbs[i].skb_dma); | ||
829 | lp->rx_skbs[i].skb = NULL; | ||
830 | } | ||
831 | pci_free_consistent(lp->pci_dev, | ||
832 | PAGE_SIZE * FD_PAGE_NUM, | ||
833 | lp->fd_buf, | ||
834 | lp->fd_buf_dma); | ||
835 | lp->fd_buf = NULL; | ||
650 | return -ENOMEM; | 836 | return -ENOMEM; |
651 | } | 837 | } |
652 | #ifdef __mips__ | ||
653 | dma_cache_wback_inv((unsigned long)lp->data_buf[i], PAGE_SIZE * FD_PAGE_NUM); | ||
654 | #endif | 838 | #endif |
655 | } | 839 | } |
656 | #ifdef __mips__ | 840 | printk(KERN_DEBUG "%s: FD buf %p DataBuf", |
657 | dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); | 841 | dev->name, lp->fd_buf); |
842 | #ifdef TC35815_USE_PACKEDBUFFER | ||
843 | printk(" DataBuf"); | ||
844 | for (i = 0; i < RX_BUF_NUM; i++) | ||
845 | printk(" %p", lp->data_buf[i]); | ||
658 | #endif | 846 | #endif |
847 | printk("\n"); | ||
659 | } else { | 848 | } else { |
660 | memset(lp->fd_buf, 0, PAGE_SIZE * FD_PAGE_NUM); | 849 | for (i = 0; i < FD_PAGE_NUM; i++) { |
661 | #ifdef __mips__ | 850 | clear_page((void *)((unsigned long)lp->fd_buf + i * PAGE_SIZE)); |
662 | dma_cache_wback_inv((unsigned long)lp->fd_buf, PAGE_SIZE * FD_PAGE_NUM); | 851 | } |
663 | #endif | ||
664 | } | 852 | } |
665 | #ifdef __mips__ | ||
666 | fd_addr = (unsigned long)vtonocache(lp->fd_buf); | ||
667 | #else | ||
668 | fd_addr = (unsigned long)lp->fd_buf; | 853 | fd_addr = (unsigned long)lp->fd_buf; |
669 | #endif | ||
670 | 854 | ||
671 | /* Free Descriptors (for Receive) */ | 855 | /* Free Descriptors (for Receive) */ |
672 | lp->rfd_base = (struct RxFD *)fd_addr; | 856 | lp->rfd_base = (struct RxFD *)fd_addr; |
@@ -675,34 +859,66 @@ tc35815_init_queues(struct net_device *dev) | |||
675 | lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD); | 859 | lp->rfd_base[i].fd.FDCtl = cpu_to_le32(FD_CownsFD); |
676 | } | 860 | } |
677 | lp->rfd_cur = lp->rfd_base; | 861 | lp->rfd_cur = lp->rfd_base; |
678 | lp->rfd_limit = (struct RxFD *)(fd_addr - | 862 | lp->rfd_limit = (struct RxFD *)fd_addr - (RX_FD_RESERVE + 1); |
679 | sizeof(struct FDesc) - | ||
680 | sizeof(struct BDesc) * 30); | ||
681 | 863 | ||
682 | /* Transmit Descriptors */ | 864 | /* Transmit Descriptors */ |
683 | lp->tfd_base = (struct TxFD *)fd_addr; | 865 | lp->tfd_base = (struct TxFD *)fd_addr; |
684 | fd_addr += sizeof(struct TxFD) * TX_FD_NUM; | 866 | fd_addr += sizeof(struct TxFD) * TX_FD_NUM; |
685 | for (i = 0; i < TX_FD_NUM; i++) { | 867 | for (i = 0; i < TX_FD_NUM; i++) { |
686 | lp->tfd_base[i].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[i+1])); | 868 | lp->tfd_base[i].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[i+1])); |
687 | lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); | 869 | lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); |
688 | lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0); | 870 | lp->tfd_base[i].fd.FDCtl = cpu_to_le32(0); |
689 | } | 871 | } |
690 | lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(virt_to_bus(&lp->tfd_base[0])); | 872 | lp->tfd_base[TX_FD_NUM-1].fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, &lp->tfd_base[0])); |
691 | lp->tfd_start = 0; | 873 | lp->tfd_start = 0; |
692 | lp->tfd_end = 0; | 874 | lp->tfd_end = 0; |
693 | 875 | ||
694 | /* Buffer List (for Receive) */ | 876 | /* Buffer List (for Receive) */ |
695 | lp->fbl_ptr = (struct FrFD *)fd_addr; | 877 | lp->fbl_ptr = (struct FrFD *)fd_addr; |
696 | lp->fbl_ptr->fd.FDNext = cpu_to_le32(virt_to_bus(lp->fbl_ptr)); | 878 | lp->fbl_ptr->fd.FDNext = cpu_to_le32(fd_virt_to_bus(lp, lp->fbl_ptr)); |
697 | lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_PAGES | FD_CownsFD); | 879 | lp->fbl_ptr->fd.FDCtl = cpu_to_le32(RX_BUF_NUM | FD_CownsFD); |
698 | for (i = 0; i < RX_BUF_PAGES; i++) { | 880 | #ifndef TC35815_USE_PACKEDBUFFER |
699 | lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(virt_to_bus(lp->data_buf[i])); | 881 | /* |
882 | * move all allocated skbs to head of rx_skbs[] array. | ||
883 | * fbl_count mighe not be RX_BUF_NUM if alloc_rxbuf_skb() in | ||
884 | * tc35815_rx() had failed. | ||
885 | */ | ||
886 | lp->fbl_count = 0; | ||
887 | for (i = 0; i < RX_BUF_NUM; i++) { | ||
888 | if (lp->rx_skbs[i].skb) { | ||
889 | if (i != lp->fbl_count) { | ||
890 | lp->rx_skbs[lp->fbl_count].skb = | ||
891 | lp->rx_skbs[i].skb; | ||
892 | lp->rx_skbs[lp->fbl_count].skb_dma = | ||
893 | lp->rx_skbs[i].skb_dma; | ||
894 | } | ||
895 | lp->fbl_count++; | ||
896 | } | ||
897 | } | ||
898 | #endif | ||
899 | for (i = 0; i < RX_BUF_NUM; i++) { | ||
900 | #ifdef TC35815_USE_PACKEDBUFFER | ||
901 | lp->fbl_ptr->bd[i].BuffData = cpu_to_le32(lp->data_buf_dma[i]); | ||
902 | #else | ||
903 | if (i >= lp->fbl_count) { | ||
904 | lp->fbl_ptr->bd[i].BuffData = 0; | ||
905 | lp->fbl_ptr->bd[i].BDCtl = 0; | ||
906 | continue; | ||
907 | } | ||
908 | lp->fbl_ptr->bd[i].BuffData = | ||
909 | cpu_to_le32(lp->rx_skbs[i].skb_dma); | ||
910 | #endif | ||
700 | /* BDID is index of FrFD.bd[] */ | 911 | /* BDID is index of FrFD.bd[] */ |
701 | lp->fbl_ptr->bd[i].BDCtl = | 912 | lp->fbl_ptr->bd[i].BDCtl = |
702 | cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | PAGE_SIZE); | 913 | cpu_to_le32(BD_CownsBD | (i << BD_RxBDID_SHIFT) | |
914 | RX_BUF_SIZE); | ||
703 | } | 915 | } |
916 | #ifdef TC35815_USE_PACKEDBUFFER | ||
704 | lp->fbl_curid = 0; | 917 | lp->fbl_curid = 0; |
918 | #endif | ||
705 | 919 | ||
920 | printk(KERN_DEBUG "%s: TxFD %p RxFD %p FrFD %p\n", | ||
921 | dev->name, lp->tfd_base, lp->rfd_base, lp->fbl_ptr); | ||
706 | return 0; | 922 | return 0; |
707 | } | 923 | } |
708 | 924 | ||
@@ -713,11 +929,25 @@ tc35815_clear_queues(struct net_device *dev) | |||
713 | int i; | 929 | int i; |
714 | 930 | ||
715 | for (i = 0; i < TX_FD_NUM; i++) { | 931 | for (i = 0; i < TX_FD_NUM; i++) { |
716 | struct sk_buff *skb = (struct sk_buff *) | 932 | u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem); |
717 | le32_to_cpu(lp->tfd_base[i].fd.FDSystem); | 933 | struct sk_buff *skb = |
718 | if (skb) | 934 | fdsystem != 0xffffffff ? |
935 | lp->tx_skbs[fdsystem].skb : NULL; | ||
936 | #ifdef DEBUG | ||
937 | if (lp->tx_skbs[i].skb != skb) { | ||
938 | printk("%s: tx_skbs mismatch(%d).\n", dev->name, i); | ||
939 | panic_queues(dev); | ||
940 | } | ||
941 | #else | ||
942 | BUG_ON(lp->tx_skbs[i].skb != skb); | ||
943 | #endif | ||
944 | if (skb) { | ||
945 | pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE); | ||
946 | lp->tx_skbs[i].skb = NULL; | ||
947 | lp->tx_skbs[i].skb_dma = 0; | ||
719 | dev_kfree_skb_any(skb); | 948 | dev_kfree_skb_any(skb); |
720 | lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); | 949 | } |
950 | lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); | ||
721 | } | 951 | } |
722 | 952 | ||
723 | tc35815_init_queues(dev); | 953 | tc35815_init_queues(dev); |
@@ -731,28 +961,53 @@ tc35815_free_queues(struct net_device *dev) | |||
731 | 961 | ||
732 | if (lp->tfd_base) { | 962 | if (lp->tfd_base) { |
733 | for (i = 0; i < TX_FD_NUM; i++) { | 963 | for (i = 0; i < TX_FD_NUM; i++) { |
734 | struct sk_buff *skb = (struct sk_buff *) | 964 | u32 fdsystem = le32_to_cpu(lp->tfd_base[i].fd.FDSystem); |
735 | le32_to_cpu(lp->tfd_base[i].fd.FDSystem); | 965 | struct sk_buff *skb = |
736 | if (skb) | 966 | fdsystem != 0xffffffff ? |
737 | dev_kfree_skb_any(skb); | 967 | lp->tx_skbs[fdsystem].skb : NULL; |
738 | lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0); | 968 | #ifdef DEBUG |
969 | if (lp->tx_skbs[i].skb != skb) { | ||
970 | printk("%s: tx_skbs mismatch(%d).\n", dev->name, i); | ||
971 | panic_queues(dev); | ||
972 | } | ||
973 | #else | ||
974 | BUG_ON(lp->tx_skbs[i].skb != skb); | ||
975 | #endif | ||
976 | if (skb) { | ||
977 | dev_kfree_skb(skb); | ||
978 | pci_unmap_single(lp->pci_dev, lp->tx_skbs[i].skb_dma, skb->len, PCI_DMA_TODEVICE); | ||
979 | lp->tx_skbs[i].skb = NULL; | ||
980 | lp->tx_skbs[i].skb_dma = 0; | ||
981 | } | ||
982 | lp->tfd_base[i].fd.FDSystem = cpu_to_le32(0xffffffff); | ||
739 | } | 983 | } |
740 | } | 984 | } |
741 | 985 | ||
742 | lp->rfd_base = NULL; | 986 | lp->rfd_base = NULL; |
743 | lp->rfd_base = NULL; | ||
744 | lp->rfd_limit = NULL; | 987 | lp->rfd_limit = NULL; |
745 | lp->rfd_cur = NULL; | 988 | lp->rfd_cur = NULL; |
746 | lp->fbl_ptr = NULL; | 989 | lp->fbl_ptr = NULL; |
747 | 990 | ||
748 | for (i = 0; i < RX_BUF_PAGES; i++) { | 991 | for (i = 0; i < RX_BUF_NUM; i++) { |
749 | if (lp->data_buf[i]) | 992 | #ifdef TC35815_USE_PACKEDBUFFER |
750 | free_page((unsigned long)lp->data_buf[i]); | 993 | if (lp->data_buf[i]) { |
751 | lp->data_buf[i] = 0; | 994 | free_rxbuf_page(lp->pci_dev, |
995 | lp->data_buf[i], lp->data_buf_dma[i]); | ||
996 | lp->data_buf[i] = NULL; | ||
997 | } | ||
998 | #else | ||
999 | if (lp->rx_skbs[i].skb) { | ||
1000 | free_rxbuf_skb(lp->pci_dev, lp->rx_skbs[i].skb, | ||
1001 | lp->rx_skbs[i].skb_dma); | ||
1002 | lp->rx_skbs[i].skb = NULL; | ||
1003 | } | ||
1004 | #endif | ||
1005 | } | ||
1006 | if (lp->fd_buf) { | ||
1007 | pci_free_consistent(lp->pci_dev, PAGE_SIZE * FD_PAGE_NUM, | ||
1008 | lp->fd_buf, lp->fd_buf_dma); | ||
1009 | lp->fd_buf = NULL; | ||
752 | } | 1010 | } |
753 | if (lp->fd_buf) | ||
754 | __free_pages(lp->fd_buf, FD_PAGE_ORDER); | ||
755 | lp->fd_buf = NULL; | ||
756 | } | 1011 | } |
757 | 1012 | ||
758 | static void | 1013 | static void |
@@ -792,6 +1047,7 @@ dump_rxfd(struct RxFD *fd) | |||
792 | return bd_count; | 1047 | return bd_count; |
793 | } | 1048 | } |
794 | 1049 | ||
1050 | #if defined(DEBUG) || defined(TC35815_USE_PACKEDBUFFER) | ||
795 | static void | 1051 | static void |
796 | dump_frfd(struct FrFD *fd) | 1052 | dump_frfd(struct FrFD *fd) |
797 | { | 1053 | { |
@@ -802,20 +1058,22 @@ dump_frfd(struct FrFD *fd) | |||
802 | le32_to_cpu(fd->fd.FDStat), | 1058 | le32_to_cpu(fd->fd.FDStat), |
803 | le32_to_cpu(fd->fd.FDCtl)); | 1059 | le32_to_cpu(fd->fd.FDCtl)); |
804 | printk("BD: "); | 1060 | printk("BD: "); |
805 | for (i = 0; i < RX_BUF_PAGES; i++) | 1061 | for (i = 0; i < RX_BUF_NUM; i++) |
806 | printk(" %08x %08x", | 1062 | printk(" %08x %08x", |
807 | le32_to_cpu(fd->bd[i].BuffData), | 1063 | le32_to_cpu(fd->bd[i].BuffData), |
808 | le32_to_cpu(fd->bd[i].BDCtl)); | 1064 | le32_to_cpu(fd->bd[i].BDCtl)); |
809 | printk("\n"); | 1065 | printk("\n"); |
810 | } | 1066 | } |
1067 | #endif | ||
811 | 1068 | ||
1069 | #ifdef DEBUG | ||
812 | static void | 1070 | static void |
813 | panic_queues(struct net_device *dev) | 1071 | panic_queues(struct net_device *dev) |
814 | { | 1072 | { |
815 | struct tc35815_local *lp = dev->priv; | 1073 | struct tc35815_local *lp = dev->priv; |
816 | int i; | 1074 | int i; |
817 | 1075 | ||
818 | printk("TxFD base %p, start %d, end %d\n", | 1076 | printk("TxFD base %p, start %u, end %u\n", |
819 | lp->tfd_base, lp->tfd_start, lp->tfd_end); | 1077 | lp->tfd_base, lp->tfd_start, lp->tfd_end); |
820 | printk("RxFD base %p limit %p cur %p\n", | 1078 | printk("RxFD base %p limit %p cur %p\n", |
821 | lp->rfd_base, lp->rfd_limit, lp->rfd_cur); | 1079 | lp->rfd_base, lp->rfd_limit, lp->rfd_cur); |
@@ -829,31 +1087,13 @@ panic_queues(struct net_device *dev) | |||
829 | dump_frfd(lp->fbl_ptr); | 1087 | dump_frfd(lp->fbl_ptr); |
830 | panic("%s: Illegal queue state.", dev->name); | 1088 | panic("%s: Illegal queue state.", dev->name); |
831 | } | 1089 | } |
832 | |||
833 | #if 0 | ||
834 | static void print_buf(char *add, int length) | ||
835 | { | ||
836 | int i; | ||
837 | int len = length; | ||
838 | |||
839 | printk("print_buf(%08x)(%x)\n", (unsigned int) add,length); | ||
840 | |||
841 | if (len > 100) | ||
842 | len = 100; | ||
843 | for (i = 0; i < len; i++) { | ||
844 | printk(" %2.2X", (unsigned char) add[i]); | ||
845 | if (!(i % 16)) | ||
846 | printk("\n"); | ||
847 | } | ||
848 | printk("\n"); | ||
849 | } | ||
850 | #endif | 1090 | #endif |
851 | 1091 | ||
852 | static void print_eth(char *add) | 1092 | static void print_eth(char *add) |
853 | { | 1093 | { |
854 | int i; | 1094 | int i; |
855 | 1095 | ||
856 | printk("print_eth(%08x)\n", (unsigned int) add); | 1096 | printk("print_eth(%p)\n", add); |
857 | for (i = 0; i < 6; i++) | 1097 | for (i = 0; i < 6; i++) |
858 | printk(" %2.2X", (unsigned char) add[i + 6]); | 1098 | printk(" %2.2X", (unsigned char) add[i + 6]); |
859 | printk(" =>"); | 1099 | printk(" =>"); |
@@ -862,6 +1102,73 @@ static void print_eth(char *add) | |||
862 | printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); | 1102 | printk(" : %2.2X%2.2X\n", (unsigned char) add[12], (unsigned char) add[13]); |
863 | } | 1103 | } |
864 | 1104 | ||
1105 | static int tc35815_tx_full(struct net_device *dev) | ||
1106 | { | ||
1107 | struct tc35815_local *lp = dev->priv; | ||
1108 | return ((lp->tfd_start + 1) % TX_FD_NUM == lp->tfd_end); | ||
1109 | } | ||
1110 | |||
1111 | static void tc35815_restart(struct net_device *dev) | ||
1112 | { | ||
1113 | struct tc35815_local *lp = dev->priv; | ||
1114 | int pid = lp->phy_addr; | ||
1115 | int do_phy_reset = 1; | ||
1116 | del_timer(&lp->timer); /* Kill if running */ | ||
1117 | |||
1118 | if (lp->mii_id[0] == 0x0016 && (lp->mii_id[1] & 0xfc00) == 0xf800) { | ||
1119 | /* Resetting PHY cause problem on some chip... (SEEQ 80221) */ | ||
1120 | do_phy_reset = 0; | ||
1121 | } | ||
1122 | if (do_phy_reset) { | ||
1123 | int timeout; | ||
1124 | tc_mdio_write(dev, pid, MII_BMCR, BMCR_RESET); | ||
1125 | timeout = 100; | ||
1126 | while (--timeout) { | ||
1127 | if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_RESET)) | ||
1128 | break; | ||
1129 | udelay(1); | ||
1130 | } | ||
1131 | if (!timeout) | ||
1132 | printk(KERN_ERR "%s: BMCR reset failed.\n", dev->name); | ||
1133 | } | ||
1134 | |||
1135 | tc35815_chip_reset(dev); | ||
1136 | tc35815_clear_queues(dev); | ||
1137 | tc35815_chip_init(dev); | ||
1138 | /* Reconfigure CAM again since tc35815_chip_init() initialize it. */ | ||
1139 | tc35815_set_multicast_list(dev); | ||
1140 | } | ||
1141 | |||
1142 | static void tc35815_tx_timeout(struct net_device *dev) | ||
1143 | { | ||
1144 | struct tc35815_local *lp = dev->priv; | ||
1145 | struct tc35815_regs __iomem *tr = | ||
1146 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
1147 | |||
1148 | printk(KERN_WARNING "%s: transmit timed out, status %#x\n", | ||
1149 | dev->name, tc_readl(&tr->Tx_Stat)); | ||
1150 | |||
1151 | /* Try to restart the adaptor. */ | ||
1152 | spin_lock_irq(&lp->lock); | ||
1153 | tc35815_restart(dev); | ||
1154 | spin_unlock_irq(&lp->lock); | ||
1155 | |||
1156 | lp->stats.tx_errors++; | ||
1157 | |||
1158 | /* If we have space available to accept new transmit | ||
1159 | * requests, wake up the queueing layer. This would | ||
1160 | * be the case if the chipset_init() call above just | ||
1161 | * flushes out the tx queue and empties it. | ||
1162 | * | ||
1163 | * If instead, the tx queue is retained then the | ||
1164 | * netif_wake_queue() call should be placed in the | ||
1165 | * TX completion interrupt handler of the driver instead | ||
1166 | * of here. | ||
1167 | */ | ||
1168 | if (!tc35815_tx_full(dev)) | ||
1169 | netif_wake_queue(dev); | ||
1170 | } | ||
1171 | |||
865 | /* | 1172 | /* |
866 | * Open/initialize the board. This is called (in the current kernel) | 1173 | * Open/initialize the board. This is called (in the current kernel) |
867 | * sometime after booting when the 'ifconfig' program is run. | 1174 | * sometime after booting when the 'ifconfig' program is run. |
@@ -874,16 +1181,16 @@ static int | |||
874 | tc35815_open(struct net_device *dev) | 1181 | tc35815_open(struct net_device *dev) |
875 | { | 1182 | { |
876 | struct tc35815_local *lp = dev->priv; | 1183 | struct tc35815_local *lp = dev->priv; |
1184 | |||
877 | /* | 1185 | /* |
878 | * This is used if the interrupt line can turned off (shared). | 1186 | * This is used if the interrupt line can turned off (shared). |
879 | * See 3c503.c for an example of selecting the IRQ at config-time. | 1187 | * See 3c503.c for an example of selecting the IRQ at config-time. |
880 | */ | 1188 | */ |
881 | 1189 | if (request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, dev->name, dev)) { | |
882 | if (dev->irq == 0 || | ||
883 | request_irq(dev->irq, &tc35815_interrupt, IRQF_SHARED, cardname, dev)) { | ||
884 | return -EAGAIN; | 1190 | return -EAGAIN; |
885 | } | 1191 | } |
886 | 1192 | ||
1193 | del_timer(&lp->timer); /* Kill if running */ | ||
887 | tc35815_chip_reset(dev); | 1194 | tc35815_chip_reset(dev); |
888 | 1195 | ||
889 | if (tc35815_init_queues(dev) != 0) { | 1196 | if (tc35815_init_queues(dev) != 0) { |
@@ -892,138 +1199,119 @@ tc35815_open(struct net_device *dev) | |||
892 | } | 1199 | } |
893 | 1200 | ||
894 | /* Reset the hardware here. Don't forget to set the station address. */ | 1201 | /* Reset the hardware here. Don't forget to set the station address. */ |
1202 | spin_lock_irq(&lp->lock); | ||
895 | tc35815_chip_init(dev); | 1203 | tc35815_chip_init(dev); |
1204 | spin_unlock_irq(&lp->lock); | ||
896 | 1205 | ||
897 | lp->tbusy = 0; | 1206 | /* We are now ready to accept transmit requeusts from |
1207 | * the queueing layer of the networking. | ||
1208 | */ | ||
898 | netif_start_queue(dev); | 1209 | netif_start_queue(dev); |
899 | 1210 | ||
900 | return 0; | 1211 | return 0; |
901 | } | 1212 | } |
902 | 1213 | ||
903 | static void tc35815_tx_timeout(struct net_device *dev) | 1214 | /* This will only be invoked if your driver is _not_ in XOFF state. |
904 | { | 1215 | * What this means is that you need not check it, and that this |
905 | struct tc35815_local *lp = dev->priv; | 1216 | * invariant will hold if you make sure that the netif_*_queue() |
906 | struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; | 1217 | * calls are done at the proper times. |
907 | unsigned long flags; | 1218 | */ |
908 | |||
909 | spin_lock_irqsave(&lp->lock, flags); | ||
910 | printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", | ||
911 | dev->name, tc_readl(&tr->Tx_Stat)); | ||
912 | /* Try to restart the adaptor. */ | ||
913 | tc35815_chip_reset(dev); | ||
914 | tc35815_clear_queues(dev); | ||
915 | tc35815_chip_init(dev); | ||
916 | lp->tbusy=0; | ||
917 | spin_unlock_irqrestore(&lp->lock, flags); | ||
918 | dev->trans_start = jiffies; | ||
919 | netif_wake_queue(dev); | ||
920 | } | ||
921 | |||
922 | static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) | 1219 | static int tc35815_send_packet(struct sk_buff *skb, struct net_device *dev) |
923 | { | 1220 | { |
924 | struct tc35815_local *lp = dev->priv; | 1221 | struct tc35815_local *lp = dev->priv; |
925 | struct tc35815_regs *tr = (struct tc35815_regs *)dev->base_addr; | 1222 | struct TxFD *txfd; |
926 | 1223 | unsigned long flags; | |
927 | if (netif_queue_stopped(dev)) { | ||
928 | /* | ||
929 | * If we get here, some higher level has decided we are broken. | ||
930 | * There should really be a "kick me" function call instead. | ||
931 | */ | ||
932 | int tickssofar = jiffies - dev->trans_start; | ||
933 | if (tickssofar < 5) | ||
934 | return 1; | ||
935 | printk(KERN_WARNING "%s: transmit timed out, status %#lx\n", | ||
936 | dev->name, tc_readl(&tr->Tx_Stat)); | ||
937 | /* Try to restart the adaptor. */ | ||
938 | tc35815_chip_reset(dev); | ||
939 | tc35815_clear_queues(dev); | ||
940 | tc35815_chip_init(dev); | ||
941 | lp->tbusy=0; | ||
942 | dev->trans_start = jiffies; | ||
943 | netif_wake_queue(dev); | ||
944 | } | ||
945 | 1224 | ||
946 | /* | 1225 | /* If some error occurs while trying to transmit this |
947 | * Block a timer-based transmit from overlapping. This could better be | 1226 | * packet, you should return '1' from this function. |
948 | * done with atomic_swap(1, lp->tbusy), but set_bit() works as well. | 1227 | * In such a case you _may not_ do anything to the |
1228 | * SKB, it is still owned by the network queueing | ||
1229 | * layer when an error is returned. This means you | ||
1230 | * may not modify any SKB fields, you may not free | ||
1231 | * the SKB, etc. | ||
949 | */ | 1232 | */ |
950 | if (test_and_set_bit(0, (void*)&lp->tbusy) != 0) { | ||
951 | printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); | ||
952 | dev_kfree_skb_any(skb); | ||
953 | } else { | ||
954 | short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; | ||
955 | unsigned char *buf = skb->data; | ||
956 | struct TxFD *txfd = &lp->tfd_base[lp->tfd_start]; | ||
957 | unsigned long flags; | ||
958 | lp->stats.tx_bytes += skb->len; | ||
959 | 1233 | ||
1234 | /* This is the most common case for modern hardware. | ||
1235 | * The spinlock protects this code from the TX complete | ||
1236 | * hardware interrupt handler. Queue flow control is | ||
1237 | * thus managed under this lock as well. | ||
1238 | */ | ||
1239 | spin_lock_irqsave(&lp->lock, flags); | ||
960 | 1240 | ||
961 | #ifdef __mips__ | 1241 | /* failsafe... (handle txdone now if half of FDs are used) */ |
962 | dma_cache_wback_inv((unsigned long)buf, length); | 1242 | if ((lp->tfd_start + TX_FD_NUM - lp->tfd_end) % TX_FD_NUM > |
1243 | TX_FD_NUM / 2) | ||
1244 | tc35815_txdone(dev); | ||
1245 | |||
1246 | if (netif_msg_pktdata(lp)) | ||
1247 | print_eth(skb->data); | ||
1248 | #ifdef DEBUG | ||
1249 | if (lp->tx_skbs[lp->tfd_start].skb) { | ||
1250 | printk("%s: tx_skbs conflict.\n", dev->name); | ||
1251 | panic_queues(dev); | ||
1252 | } | ||
1253 | #else | ||
1254 | BUG_ON(lp->tx_skbs[lp->tfd_start].skb); | ||
963 | #endif | 1255 | #endif |
964 | 1256 | lp->tx_skbs[lp->tfd_start].skb = skb; | |
965 | spin_lock_irqsave(&lp->lock, flags); | 1257 | lp->tx_skbs[lp->tfd_start].skb_dma = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); |
966 | 1258 | ||
967 | /* failsafe... */ | 1259 | /*add to ring */ |
968 | if (lp->tfd_start != lp->tfd_end) | 1260 | txfd = &lp->tfd_base[lp->tfd_start]; |
969 | tc35815_txdone(dev); | 1261 | txfd->bd.BuffData = cpu_to_le32(lp->tx_skbs[lp->tfd_start].skb_dma); |
970 | 1262 | txfd->bd.BDCtl = cpu_to_le32(skb->len); | |
971 | 1263 | txfd->fd.FDSystem = cpu_to_le32(lp->tfd_start); | |
972 | txfd->bd.BuffData = cpu_to_le32(virt_to_bus(buf)); | 1264 | txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT)); |
973 | 1265 | ||
974 | txfd->bd.BDCtl = cpu_to_le32(length); | 1266 | if (lp->tfd_start == lp->tfd_end) { |
975 | txfd->fd.FDSystem = cpu_to_le32((__u32)skb); | 1267 | struct tc35815_regs __iomem *tr = |
976 | txfd->fd.FDCtl = cpu_to_le32(FD_CownsFD | (1 << FD_BDCnt_SHIFT)); | 1268 | (struct tc35815_regs __iomem *)dev->base_addr; |
977 | 1269 | /* Start DMA Transmitter. */ | |
978 | if (lp->tfd_start == lp->tfd_end) { | 1270 | txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL); |
979 | /* Start DMA Transmitter. */ | ||
980 | txfd->fd.FDNext |= cpu_to_le32(FD_Next_EOL); | ||
981 | #ifdef GATHER_TXINT | 1271 | #ifdef GATHER_TXINT |
982 | txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); | 1272 | txfd->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); |
983 | #endif | 1273 | #endif |
984 | if (tc35815_debug > 2) { | 1274 | if (netif_msg_tx_queued(lp)) { |
985 | printk("%s: starting TxFD.\n", dev->name); | 1275 | printk("%s: starting TxFD.\n", dev->name); |
986 | dump_txfd(txfd); | 1276 | dump_txfd(txfd); |
987 | if (tc35815_debug > 3) | ||
988 | print_eth(buf); | ||
989 | } | ||
990 | tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); | ||
991 | } else { | ||
992 | txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL); | ||
993 | if (tc35815_debug > 2) { | ||
994 | printk("%s: queueing TxFD.\n", dev->name); | ||
995 | dump_txfd(txfd); | ||
996 | if (tc35815_debug > 3) | ||
997 | print_eth(buf); | ||
998 | } | ||
999 | } | 1277 | } |
1000 | lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM; | 1278 | tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr); |
1279 | } else { | ||
1280 | txfd->fd.FDNext &= cpu_to_le32(~FD_Next_EOL); | ||
1281 | if (netif_msg_tx_queued(lp)) { | ||
1282 | printk("%s: queueing TxFD.\n", dev->name); | ||
1283 | dump_txfd(txfd); | ||
1284 | } | ||
1285 | } | ||
1286 | lp->tfd_start = (lp->tfd_start + 1) % TX_FD_NUM; | ||
1001 | 1287 | ||
1002 | dev->trans_start = jiffies; | 1288 | dev->trans_start = jiffies; |
1003 | 1289 | ||
1004 | if ((lp->tfd_start + 1) % TX_FD_NUM != lp->tfd_end) { | 1290 | /* If we just used up the very last entry in the |
1005 | /* we can send another packet */ | 1291 | * TX ring on this device, tell the queueing |
1006 | lp->tbusy = 0; | 1292 | * layer to send no more. |
1007 | netif_start_queue(dev); | 1293 | */ |
1008 | } else { | 1294 | if (tc35815_tx_full(dev)) { |
1009 | netif_stop_queue(dev); | 1295 | if (netif_msg_tx_queued(lp)) |
1010 | if (tc35815_debug > 1) | 1296 | printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name); |
1011 | printk(KERN_WARNING "%s: TxFD Exhausted.\n", dev->name); | 1297 | netif_stop_queue(dev); |
1012 | } | ||
1013 | spin_unlock_irqrestore(&lp->lock, flags); | ||
1014 | } | 1298 | } |
1015 | 1299 | ||
1300 | /* When the TX completion hw interrupt arrives, this | ||
1301 | * is when the transmit statistics are updated. | ||
1302 | */ | ||
1303 | |||
1304 | spin_unlock_irqrestore(&lp->lock, flags); | ||
1016 | return 0; | 1305 | return 0; |
1017 | } | 1306 | } |
1018 | 1307 | ||
1019 | #define FATAL_ERROR_INT \ | 1308 | #define FATAL_ERROR_INT \ |
1020 | (Int_IntPCI | Int_DmParErr | Int_IntNRAbt) | 1309 | (Int_IntPCI | Int_DmParErr | Int_IntNRAbt) |
1021 | static void tc35815_fatal_error_interrupt(struct net_device *dev, int status) | 1310 | static void tc35815_fatal_error_interrupt(struct net_device *dev, u32 status) |
1022 | { | 1311 | { |
1023 | static int count; | 1312 | static int count; |
1024 | printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):", | 1313 | printk(KERN_WARNING "%s: Fatal Error Intterrupt (%#x):", |
1025 | dev->name, status); | 1314 | dev->name, status); |
1026 | |||
1027 | if (status & Int_IntPCI) | 1315 | if (status & Int_IntPCI) |
1028 | printk(" IntPCI"); | 1316 | printk(" IntPCI"); |
1029 | if (status & Int_DmParErr) | 1317 | if (status & Int_DmParErr) |
@@ -1033,110 +1321,170 @@ static void tc35815_fatal_error_interrupt(struct net_device *dev, int status) | |||
1033 | printk("\n"); | 1321 | printk("\n"); |
1034 | if (count++ > 100) | 1322 | if (count++ > 100) |
1035 | panic("%s: Too many fatal errors.", dev->name); | 1323 | panic("%s: Too many fatal errors.", dev->name); |
1036 | printk(KERN_WARNING "%s: Resetting %s...\n", dev->name, cardname); | 1324 | printk(KERN_WARNING "%s: Resetting ...\n", dev->name); |
1037 | /* Try to restart the adaptor. */ | 1325 | /* Try to restart the adaptor. */ |
1038 | tc35815_chip_reset(dev); | 1326 | tc35815_restart(dev); |
1039 | tc35815_clear_queues(dev); | 1327 | } |
1040 | tc35815_chip_init(dev); | 1328 | |
1329 | #ifdef TC35815_NAPI | ||
1330 | static int tc35815_do_interrupt(struct net_device *dev, u32 status, int limit) | ||
1331 | #else | ||
1332 | static int tc35815_do_interrupt(struct net_device *dev, u32 status) | ||
1333 | #endif | ||
1334 | { | ||
1335 | struct tc35815_local *lp = dev->priv; | ||
1336 | struct tc35815_regs __iomem *tr = | ||
1337 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
1338 | int ret = -1; | ||
1339 | |||
1340 | /* Fatal errors... */ | ||
1341 | if (status & FATAL_ERROR_INT) { | ||
1342 | tc35815_fatal_error_interrupt(dev, status); | ||
1343 | return 0; | ||
1344 | } | ||
1345 | /* recoverable errors */ | ||
1346 | if (status & Int_IntFDAEx) { | ||
1347 | /* disable FDAEx int. (until we make rooms...) */ | ||
1348 | tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); | ||
1349 | printk(KERN_WARNING | ||
1350 | "%s: Free Descriptor Area Exhausted (%#x).\n", | ||
1351 | dev->name, status); | ||
1352 | lp->stats.rx_dropped++; | ||
1353 | ret = 0; | ||
1354 | } | ||
1355 | if (status & Int_IntBLEx) { | ||
1356 | /* disable BLEx int. (until we make rooms...) */ | ||
1357 | tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); | ||
1358 | printk(KERN_WARNING | ||
1359 | "%s: Buffer List Exhausted (%#x).\n", | ||
1360 | dev->name, status); | ||
1361 | lp->stats.rx_dropped++; | ||
1362 | ret = 0; | ||
1363 | } | ||
1364 | if (status & Int_IntExBD) { | ||
1365 | printk(KERN_WARNING | ||
1366 | "%s: Excessive Buffer Descriptiors (%#x).\n", | ||
1367 | dev->name, status); | ||
1368 | lp->stats.rx_length_errors++; | ||
1369 | ret = 0; | ||
1370 | } | ||
1371 | |||
1372 | /* normal notification */ | ||
1373 | if (status & Int_IntMacRx) { | ||
1374 | /* Got a packet(s). */ | ||
1375 | #ifdef TC35815_NAPI | ||
1376 | ret = tc35815_rx(dev, limit); | ||
1377 | #else | ||
1378 | tc35815_rx(dev); | ||
1379 | ret = 0; | ||
1380 | #endif | ||
1381 | lp->lstats.rx_ints++; | ||
1382 | } | ||
1383 | if (status & Int_IntMacTx) { | ||
1384 | /* Transmit complete. */ | ||
1385 | lp->lstats.tx_ints++; | ||
1386 | tc35815_txdone(dev); | ||
1387 | netif_wake_queue(dev); | ||
1388 | ret = 0; | ||
1389 | } | ||
1390 | return ret; | ||
1041 | } | 1391 | } |
1042 | 1392 | ||
1043 | /* | 1393 | /* |
1044 | * The typical workload of the driver: | 1394 | * The typical workload of the driver: |
1045 | * Handle the network interface interrupts. | 1395 | * Handle the network interface interrupts. |
1046 | */ | 1396 | */ |
1047 | static irqreturn_t tc35815_interrupt(int irq, void *dev_id) | 1397 | static irqreturn_t tc35815_interrupt(int irq, void *dev_id) |
1048 | { | 1398 | { |
1049 | struct net_device *dev = dev_id; | 1399 | struct net_device *dev = dev_id; |
1050 | struct tc35815_regs *tr; | 1400 | struct tc35815_regs __iomem *tr = |
1051 | struct tc35815_local *lp; | 1401 | (struct tc35815_regs __iomem *)dev->base_addr; |
1052 | int status, boguscount = 0; | 1402 | #ifdef TC35815_NAPI |
1053 | int handled = 0; | 1403 | u32 dmactl = tc_readl(&tr->DMA_Ctl); |
1054 | 1404 | ||
1055 | if (dev == NULL) { | 1405 | if (!(dmactl & DMA_IntMask)) { |
1056 | printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq); | 1406 | /* disable interrupts */ |
1057 | return IRQ_NONE; | 1407 | tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl); |
1058 | } | 1408 | if (netif_rx_schedule_prep(dev)) |
1059 | 1409 | __netif_rx_schedule(dev); | |
1060 | tr = (struct tc35815_regs*)dev->base_addr; | 1410 | else { |
1061 | lp = dev->priv; | 1411 | printk(KERN_ERR "%s: interrupt taken in poll\n", |
1062 | 1412 | dev->name); | |
1063 | do { | 1413 | BUG(); |
1064 | status = tc_readl(&tr->Int_Src); | ||
1065 | if (status == 0) | ||
1066 | break; | ||
1067 | handled = 1; | ||
1068 | tc_writel(status, &tr->Int_Src); /* write to clear */ | ||
1069 | |||
1070 | /* Fatal errors... */ | ||
1071 | if (status & FATAL_ERROR_INT) { | ||
1072 | tc35815_fatal_error_interrupt(dev, status); | ||
1073 | break; | ||
1074 | } | ||
1075 | /* recoverable errors */ | ||
1076 | if (status & Int_IntFDAEx) { | ||
1077 | /* disable FDAEx int. (until we make rooms...) */ | ||
1078 | tc_writel(tc_readl(&tr->Int_En) & ~Int_FDAExEn, &tr->Int_En); | ||
1079 | printk(KERN_WARNING | ||
1080 | "%s: Free Descriptor Area Exhausted (%#x).\n", | ||
1081 | dev->name, status); | ||
1082 | lp->stats.rx_dropped++; | ||
1083 | } | ||
1084 | if (status & Int_IntBLEx) { | ||
1085 | /* disable BLEx int. (until we make rooms...) */ | ||
1086 | tc_writel(tc_readl(&tr->Int_En) & ~Int_BLExEn, &tr->Int_En); | ||
1087 | printk(KERN_WARNING | ||
1088 | "%s: Buffer List Exhausted (%#x).\n", | ||
1089 | dev->name, status); | ||
1090 | lp->stats.rx_dropped++; | ||
1091 | } | ||
1092 | if (status & Int_IntExBD) { | ||
1093 | printk(KERN_WARNING | ||
1094 | "%s: Excessive Buffer Descriptiors (%#x).\n", | ||
1095 | dev->name, status); | ||
1096 | lp->stats.rx_length_errors++; | ||
1097 | } | ||
1098 | /* normal notification */ | ||
1099 | if (status & Int_IntMacRx) { | ||
1100 | /* Got a packet(s). */ | ||
1101 | lp->lstats.rx_ints++; | ||
1102 | tc35815_rx(dev); | ||
1103 | } | ||
1104 | if (status & Int_IntMacTx) { | ||
1105 | lp->lstats.tx_ints++; | ||
1106 | tc35815_txdone(dev); | ||
1107 | } | 1414 | } |
1108 | } while (++boguscount < 20) ; | 1415 | (void)tc_readl(&tr->Int_Src); /* flush */ |
1416 | return IRQ_HANDLED; | ||
1417 | } | ||
1418 | return IRQ_NONE; | ||
1419 | #else | ||
1420 | struct tc35815_local *lp = dev->priv; | ||
1421 | int handled; | ||
1422 | u32 status; | ||
1423 | |||
1424 | spin_lock(&lp->lock); | ||
1425 | status = tc_readl(&tr->Int_Src); | ||
1426 | tc_writel(status, &tr->Int_Src); /* write to clear */ | ||
1427 | handled = tc35815_do_interrupt(dev, status); | ||
1428 | (void)tc_readl(&tr->Int_Src); /* flush */ | ||
1429 | spin_unlock(&lp->lock); | ||
1430 | return IRQ_RETVAL(handled >= 0); | ||
1431 | #endif /* TC35815_NAPI */ | ||
1432 | } | ||
1109 | 1433 | ||
1110 | return IRQ_RETVAL(handled); | 1434 | #ifdef CONFIG_NET_POLL_CONTROLLER |
1435 | static void tc35815_poll_controller(struct net_device *dev) | ||
1436 | { | ||
1437 | disable_irq(dev->irq); | ||
1438 | tc35815_interrupt(dev->irq, dev); | ||
1439 | enable_irq(dev->irq); | ||
1111 | } | 1440 | } |
1441 | #endif | ||
1112 | 1442 | ||
1113 | /* We have a good packet(s), get it/them out of the buffers. */ | 1443 | /* We have a good packet(s), get it/them out of the buffers. */ |
1444 | #ifdef TC35815_NAPI | ||
1445 | static int | ||
1446 | tc35815_rx(struct net_device *dev, int limit) | ||
1447 | #else | ||
1114 | static void | 1448 | static void |
1115 | tc35815_rx(struct net_device *dev) | 1449 | tc35815_rx(struct net_device *dev) |
1450 | #endif | ||
1116 | { | 1451 | { |
1117 | struct tc35815_local *lp = dev->priv; | 1452 | struct tc35815_local *lp = dev->priv; |
1118 | struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; | ||
1119 | unsigned int fdctl; | 1453 | unsigned int fdctl; |
1120 | int i; | 1454 | int i; |
1121 | int buf_free_count = 0; | 1455 | int buf_free_count = 0; |
1122 | int fd_free_count = 0; | 1456 | int fd_free_count = 0; |
1457 | #ifdef TC35815_NAPI | ||
1458 | int received = 0; | ||
1459 | #endif | ||
1123 | 1460 | ||
1124 | while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) { | 1461 | while (!((fdctl = le32_to_cpu(lp->rfd_cur->fd.FDCtl)) & FD_CownsFD)) { |
1125 | int status = le32_to_cpu(lp->rfd_cur->fd.FDStat); | 1462 | int status = le32_to_cpu(lp->rfd_cur->fd.FDStat); |
1126 | int pkt_len = fdctl & FD_FDLength_MASK; | 1463 | int pkt_len = fdctl & FD_FDLength_MASK; |
1127 | struct RxFD *next_rfd; | ||
1128 | int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; | 1464 | int bd_count = (fdctl & FD_BDCnt_MASK) >> FD_BDCnt_SHIFT; |
1465 | #ifdef DEBUG | ||
1466 | struct RxFD *next_rfd; | ||
1467 | #endif | ||
1468 | #if (RX_CTL_CMD & Rx_StripCRC) == 0 | ||
1469 | pkt_len -= 4; | ||
1470 | #endif | ||
1129 | 1471 | ||
1130 | if (tc35815_debug > 2) | 1472 | if (netif_msg_rx_status(lp)) |
1131 | dump_rxfd(lp->rfd_cur); | 1473 | dump_rxfd(lp->rfd_cur); |
1132 | if (status & Rx_Good) { | 1474 | if (status & Rx_Good) { |
1133 | /* Malloc up new buffer. */ | ||
1134 | struct sk_buff *skb; | 1475 | struct sk_buff *skb; |
1135 | unsigned char *data; | 1476 | unsigned char *data; |
1136 | int cur_bd, offset; | 1477 | int cur_bd; |
1137 | 1478 | #ifdef TC35815_USE_PACKEDBUFFER | |
1138 | lp->stats.rx_bytes += pkt_len; | 1479 | int offset; |
1480 | #endif | ||
1139 | 1481 | ||
1482 | #ifdef TC35815_NAPI | ||
1483 | if (--limit < 0) | ||
1484 | break; | ||
1485 | #endif | ||
1486 | #ifdef TC35815_USE_PACKEDBUFFER | ||
1487 | BUG_ON(bd_count > 2); | ||
1140 | skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ | 1488 | skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ |
1141 | if (skb == NULL) { | 1489 | if (skb == NULL) { |
1142 | printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", | 1490 | printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", |
@@ -1154,25 +1502,69 @@ tc35815_rx(struct net_device *dev) | |||
1154 | while (offset < pkt_len && cur_bd < bd_count) { | 1502 | while (offset < pkt_len && cur_bd < bd_count) { |
1155 | int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) & | 1503 | int len = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BDCtl) & |
1156 | BD_BuffLength_MASK; | 1504 | BD_BuffLength_MASK; |
1157 | void *rxbuf = | 1505 | dma_addr_t dma = le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData); |
1158 | bus_to_virt(le32_to_cpu(lp->rfd_cur->bd[cur_bd].BuffData)); | 1506 | void *rxbuf = rxbuf_bus_to_virt(lp, dma); |
1159 | #ifdef __mips__ | 1507 | if (offset + len > pkt_len) |
1160 | dma_cache_inv((unsigned long)rxbuf, len); | 1508 | len = pkt_len - offset; |
1509 | #ifdef TC35815_DMA_SYNC_ONDEMAND | ||
1510 | pci_dma_sync_single_for_cpu(lp->pci_dev, | ||
1511 | dma, len, | ||
1512 | PCI_DMA_FROMDEVICE); | ||
1161 | #endif | 1513 | #endif |
1162 | memcpy(data + offset, rxbuf, len); | 1514 | memcpy(data + offset, rxbuf, len); |
1515 | #ifdef TC35815_DMA_SYNC_ONDEMAND | ||
1516 | pci_dma_sync_single_for_device(lp->pci_dev, | ||
1517 | dma, len, | ||
1518 | PCI_DMA_FROMDEVICE); | ||
1519 | #endif | ||
1163 | offset += len; | 1520 | offset += len; |
1164 | cur_bd++; | 1521 | cur_bd++; |
1165 | } | 1522 | } |
1166 | #if 0 | 1523 | #else /* TC35815_USE_PACKEDBUFFER */ |
1167 | print_buf(data,pkt_len); | 1524 | BUG_ON(bd_count > 1); |
1525 | cur_bd = (le32_to_cpu(lp->rfd_cur->bd[0].BDCtl) | ||
1526 | & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; | ||
1527 | #ifdef DEBUG | ||
1528 | if (cur_bd >= RX_BUF_NUM) { | ||
1529 | printk("%s: invalid BDID.\n", dev->name); | ||
1530 | panic_queues(dev); | ||
1531 | } | ||
1532 | BUG_ON(lp->rx_skbs[cur_bd].skb_dma != | ||
1533 | (le32_to_cpu(lp->rfd_cur->bd[0].BuffData) & ~3)); | ||
1534 | if (!lp->rx_skbs[cur_bd].skb) { | ||
1535 | printk("%s: NULL skb.\n", dev->name); | ||
1536 | panic_queues(dev); | ||
1537 | } | ||
1538 | #else | ||
1539 | BUG_ON(cur_bd >= RX_BUF_NUM); | ||
1168 | #endif | 1540 | #endif |
1169 | if (tc35815_debug > 3) | 1541 | skb = lp->rx_skbs[cur_bd].skb; |
1542 | prefetch(skb->data); | ||
1543 | lp->rx_skbs[cur_bd].skb = NULL; | ||
1544 | lp->fbl_count--; | ||
1545 | pci_unmap_single(lp->pci_dev, | ||
1546 | lp->rx_skbs[cur_bd].skb_dma, | ||
1547 | RX_BUF_SIZE, PCI_DMA_FROMDEVICE); | ||
1548 | if (!HAVE_DMA_RXALIGN(lp)) | ||
1549 | memmove(skb->data, skb->data - 2, pkt_len); | ||
1550 | data = skb_put(skb, pkt_len); | ||
1551 | #endif /* TC35815_USE_PACKEDBUFFER */ | ||
1552 | if (netif_msg_pktdata(lp)) | ||
1170 | print_eth(data); | 1553 | print_eth(data); |
1171 | skb->protocol = eth_type_trans(skb, dev); | 1554 | skb->protocol = eth_type_trans(skb, dev); |
1555 | #ifdef TC35815_NAPI | ||
1556 | netif_receive_skb(skb); | ||
1557 | received++; | ||
1558 | #else | ||
1172 | netif_rx(skb); | 1559 | netif_rx(skb); |
1560 | #endif | ||
1561 | dev->last_rx = jiffies; | ||
1173 | lp->stats.rx_packets++; | 1562 | lp->stats.rx_packets++; |
1563 | lp->stats.rx_bytes += pkt_len; | ||
1174 | } else { | 1564 | } else { |
1175 | lp->stats.rx_errors++; | 1565 | lp->stats.rx_errors++; |
1566 | printk(KERN_DEBUG "%s: Rx error (status %x)\n", | ||
1567 | dev->name, status & Rx_Stat_Mask); | ||
1176 | /* WORKAROUND: LongErr and CRCErr means Overflow. */ | 1568 | /* WORKAROUND: LongErr and CRCErr means Overflow. */ |
1177 | if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { | 1569 | if ((status & Rx_LongErr) && (status & Rx_CRCErr)) { |
1178 | status &= ~(Rx_LongErr|Rx_CRCErr); | 1570 | status &= ~(Rx_LongErr|Rx_CRCErr); |
@@ -1189,63 +1581,150 @@ tc35815_rx(struct net_device *dev) | |||
1189 | int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl); | 1581 | int bdctl = le32_to_cpu(lp->rfd_cur->bd[bd_count - 1].BDCtl); |
1190 | unsigned char id = | 1582 | unsigned char id = |
1191 | (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; | 1583 | (bdctl & BD_RxBDID_MASK) >> BD_RxBDID_SHIFT; |
1192 | if (id >= RX_BUF_PAGES) { | 1584 | #ifdef DEBUG |
1585 | if (id >= RX_BUF_NUM) { | ||
1193 | printk("%s: invalid BDID.\n", dev->name); | 1586 | printk("%s: invalid BDID.\n", dev->name); |
1194 | panic_queues(dev); | 1587 | panic_queues(dev); |
1195 | } | 1588 | } |
1589 | #else | ||
1590 | BUG_ON(id >= RX_BUF_NUM); | ||
1591 | #endif | ||
1196 | /* free old buffers */ | 1592 | /* free old buffers */ |
1197 | while (lp->fbl_curid != id) { | 1593 | #ifdef TC35815_USE_PACKEDBUFFER |
1198 | bdctl = le32_to_cpu(lp->fbl_ptr->bd[lp->fbl_curid].BDCtl); | 1594 | while (lp->fbl_curid != id) |
1595 | #else | ||
1596 | while (lp->fbl_count < RX_BUF_NUM) | ||
1597 | #endif | ||
1598 | { | ||
1599 | #ifdef TC35815_USE_PACKEDBUFFER | ||
1600 | unsigned char curid = lp->fbl_curid; | ||
1601 | #else | ||
1602 | unsigned char curid = | ||
1603 | (id + 1 + lp->fbl_count) % RX_BUF_NUM; | ||
1604 | #endif | ||
1605 | struct BDesc *bd = &lp->fbl_ptr->bd[curid]; | ||
1606 | #ifdef DEBUG | ||
1607 | bdctl = le32_to_cpu(bd->BDCtl); | ||
1199 | if (bdctl & BD_CownsBD) { | 1608 | if (bdctl & BD_CownsBD) { |
1200 | printk("%s: Freeing invalid BD.\n", | 1609 | printk("%s: Freeing invalid BD.\n", |
1201 | dev->name); | 1610 | dev->name); |
1202 | panic_queues(dev); | 1611 | panic_queues(dev); |
1203 | } | 1612 | } |
1613 | #endif | ||
1204 | /* pass BD to controler */ | 1614 | /* pass BD to controler */ |
1615 | #ifndef TC35815_USE_PACKEDBUFFER | ||
1616 | if (!lp->rx_skbs[curid].skb) { | ||
1617 | lp->rx_skbs[curid].skb = | ||
1618 | alloc_rxbuf_skb(dev, | ||
1619 | lp->pci_dev, | ||
1620 | &lp->rx_skbs[curid].skb_dma); | ||
1621 | if (!lp->rx_skbs[curid].skb) | ||
1622 | break; /* try on next reception */ | ||
1623 | bd->BuffData = cpu_to_le32(lp->rx_skbs[curid].skb_dma); | ||
1624 | } | ||
1625 | #endif /* TC35815_USE_PACKEDBUFFER */ | ||
1205 | /* Note: BDLength was modified by chip. */ | 1626 | /* Note: BDLength was modified by chip. */ |
1206 | lp->fbl_ptr->bd[lp->fbl_curid].BDCtl = | 1627 | bd->BDCtl = cpu_to_le32(BD_CownsBD | |
1207 | cpu_to_le32(BD_CownsBD | | 1628 | (curid << BD_RxBDID_SHIFT) | |
1208 | (lp->fbl_curid << BD_RxBDID_SHIFT) | | 1629 | RX_BUF_SIZE); |
1209 | PAGE_SIZE); | 1630 | #ifdef TC35815_USE_PACKEDBUFFER |
1210 | lp->fbl_curid = | 1631 | lp->fbl_curid = (curid + 1) % RX_BUF_NUM; |
1211 | (lp->fbl_curid + 1) % RX_BUF_PAGES; | 1632 | if (netif_msg_rx_status(lp)) { |
1212 | if (tc35815_debug > 2) { | ||
1213 | printk("%s: Entering new FBD %d\n", | 1633 | printk("%s: Entering new FBD %d\n", |
1214 | dev->name, lp->fbl_curid); | 1634 | dev->name, lp->fbl_curid); |
1215 | dump_frfd(lp->fbl_ptr); | 1635 | dump_frfd(lp->fbl_ptr); |
1216 | } | 1636 | } |
1637 | #else | ||
1638 | lp->fbl_count++; | ||
1639 | #endif | ||
1217 | buf_free_count++; | 1640 | buf_free_count++; |
1218 | } | 1641 | } |
1219 | } | 1642 | } |
1220 | 1643 | ||
1221 | /* put RxFD back to controller */ | 1644 | /* put RxFD back to controller */ |
1222 | next_rfd = bus_to_virt(le32_to_cpu(lp->rfd_cur->fd.FDNext)); | 1645 | #ifdef DEBUG |
1223 | #ifdef __mips__ | 1646 | next_rfd = fd_bus_to_virt(lp, |
1224 | next_rfd = (struct RxFD *)vtonocache(next_rfd); | 1647 | le32_to_cpu(lp->rfd_cur->fd.FDNext)); |
1225 | #endif | ||
1226 | if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) { | 1648 | if (next_rfd < lp->rfd_base || next_rfd > lp->rfd_limit) { |
1227 | printk("%s: RxFD FDNext invalid.\n", dev->name); | 1649 | printk("%s: RxFD FDNext invalid.\n", dev->name); |
1228 | panic_queues(dev); | 1650 | panic_queues(dev); |
1229 | } | 1651 | } |
1652 | #endif | ||
1230 | for (i = 0; i < (bd_count + 1) / 2 + 1; i++) { | 1653 | for (i = 0; i < (bd_count + 1) / 2 + 1; i++) { |
1231 | /* pass FD to controler */ | 1654 | /* pass FD to controler */ |
1232 | lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); /* for debug */ | 1655 | #ifdef DEBUG |
1656 | lp->rfd_cur->fd.FDNext = cpu_to_le32(0xdeaddead); | ||
1657 | #else | ||
1658 | lp->rfd_cur->fd.FDNext = cpu_to_le32(FD_Next_EOL); | ||
1659 | #endif | ||
1233 | lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); | 1660 | lp->rfd_cur->fd.FDCtl = cpu_to_le32(FD_CownsFD); |
1234 | lp->rfd_cur++; | 1661 | lp->rfd_cur++; |
1235 | fd_free_count++; | 1662 | fd_free_count++; |
1236 | } | 1663 | } |
1237 | 1664 | if (lp->rfd_cur > lp->rfd_limit) | |
1238 | lp->rfd_cur = next_rfd; | 1665 | lp->rfd_cur = lp->rfd_base; |
1666 | #ifdef DEBUG | ||
1667 | if (lp->rfd_cur != next_rfd) | ||
1668 | printk("rfd_cur = %p, next_rfd %p\n", | ||
1669 | lp->rfd_cur, next_rfd); | ||
1670 | #endif | ||
1239 | } | 1671 | } |
1240 | 1672 | ||
1241 | /* re-enable BL/FDA Exhaust interrupts. */ | 1673 | /* re-enable BL/FDA Exhaust interrupts. */ |
1242 | if (fd_free_count) { | 1674 | if (fd_free_count) { |
1243 | tc_writel(tc_readl(&tr->Int_En) | Int_FDAExEn, &tr->Int_En); | 1675 | struct tc35815_regs __iomem *tr = |
1676 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
1677 | u32 en, en_old = tc_readl(&tr->Int_En); | ||
1678 | en = en_old | Int_FDAExEn; | ||
1244 | if (buf_free_count) | 1679 | if (buf_free_count) |
1245 | tc_writel(tc_readl(&tr->Int_En) | Int_BLExEn, &tr->Int_En); | 1680 | en |= Int_BLExEn; |
1681 | if (en != en_old) | ||
1682 | tc_writel(en, &tr->Int_En); | ||
1246 | } | 1683 | } |
1684 | #ifdef TC35815_NAPI | ||
1685 | return received; | ||
1686 | #endif | ||
1247 | } | 1687 | } |
1248 | 1688 | ||
1689 | #ifdef TC35815_NAPI | ||
1690 | static int | ||
1691 | tc35815_poll(struct net_device *dev, int *budget) | ||
1692 | { | ||
1693 | struct tc35815_local *lp = dev->priv; | ||
1694 | struct tc35815_regs __iomem *tr = | ||
1695 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
1696 | int limit = min(*budget, dev->quota); | ||
1697 | int received = 0, handled; | ||
1698 | u32 status; | ||
1699 | |||
1700 | spin_lock(&lp->lock); | ||
1701 | status = tc_readl(&tr->Int_Src); | ||
1702 | do { | ||
1703 | tc_writel(status, &tr->Int_Src); /* write to clear */ | ||
1704 | |||
1705 | handled = tc35815_do_interrupt(dev, status, limit); | ||
1706 | if (handled >= 0) { | ||
1707 | received += handled; | ||
1708 | limit -= handled; | ||
1709 | if (limit <= 0) | ||
1710 | break; | ||
1711 | } | ||
1712 | status = tc_readl(&tr->Int_Src); | ||
1713 | } while (status); | ||
1714 | spin_unlock(&lp->lock); | ||
1715 | |||
1716 | dev->quota -= received; | ||
1717 | *budget -= received; | ||
1718 | if (limit <= 0) | ||
1719 | return 1; | ||
1720 | |||
1721 | netif_rx_complete(dev); | ||
1722 | /* enable interrupts */ | ||
1723 | tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); | ||
1724 | return 0; | ||
1725 | } | ||
1726 | #endif | ||
1727 | |||
1249 | #ifdef NO_CHECK_CARRIER | 1728 | #ifdef NO_CHECK_CARRIER |
1250 | #define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr) | 1729 | #define TX_STA_ERR (Tx_ExColl|Tx_Under|Tx_Defer|Tx_LateColl|Tx_TxPar|Tx_SQErr) |
1251 | #else | 1730 | #else |
@@ -1264,9 +1743,17 @@ tc35815_check_tx_stat(struct net_device *dev, int status) | |||
1264 | if (status & Tx_TxColl_MASK) | 1743 | if (status & Tx_TxColl_MASK) |
1265 | lp->stats.collisions += status & Tx_TxColl_MASK; | 1744 | lp->stats.collisions += status & Tx_TxColl_MASK; |
1266 | 1745 | ||
1746 | #ifndef NO_CHECK_CARRIER | ||
1747 | /* TX4939 does not have NCarr */ | ||
1748 | if (lp->boardtype == TC35815_TX4939) | ||
1749 | status &= ~Tx_NCarr; | ||
1750 | #ifdef WORKAROUND_LOSTCAR | ||
1267 | /* WORKAROUND: ignore LostCrS in full duplex operation */ | 1751 | /* WORKAROUND: ignore LostCrS in full duplex operation */ |
1268 | if (lp->fullduplex) | 1752 | if ((lp->timer_state != asleep && lp->timer_state != lcheck) |
1753 | || lp->fullduplex) | ||
1269 | status &= ~Tx_NCarr; | 1754 | status &= ~Tx_NCarr; |
1755 | #endif | ||
1756 | #endif | ||
1270 | 1757 | ||
1271 | if (!(status & TX_STA_ERR)) { | 1758 | if (!(status & TX_STA_ERR)) { |
1272 | /* no error. */ | 1759 | /* no error. */ |
@@ -1282,6 +1769,15 @@ tc35815_check_tx_stat(struct net_device *dev, int status) | |||
1282 | if (status & Tx_Under) { | 1769 | if (status & Tx_Under) { |
1283 | lp->stats.tx_fifo_errors++; | 1770 | lp->stats.tx_fifo_errors++; |
1284 | msg = "Tx FIFO Underrun."; | 1771 | msg = "Tx FIFO Underrun."; |
1772 | if (lp->lstats.tx_underrun < TX_THRESHOLD_KEEP_LIMIT) { | ||
1773 | lp->lstats.tx_underrun++; | ||
1774 | if (lp->lstats.tx_underrun >= TX_THRESHOLD_KEEP_LIMIT) { | ||
1775 | struct tc35815_regs __iomem *tr = | ||
1776 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
1777 | tc_writel(TX_THRESHOLD_MAX, &tr->TxThrsh); | ||
1778 | msg = "Tx FIFO Underrun.Change Tx threshold to max."; | ||
1779 | } | ||
1780 | } | ||
1285 | } | 1781 | } |
1286 | if (status & Tx_Defer) { | 1782 | if (status & Tx_Defer) { |
1287 | lp->stats.tx_fifo_errors++; | 1783 | lp->stats.tx_fifo_errors++; |
@@ -1305,18 +1801,19 @@ tc35815_check_tx_stat(struct net_device *dev, int status) | |||
1305 | lp->stats.tx_heartbeat_errors++; | 1801 | lp->stats.tx_heartbeat_errors++; |
1306 | msg = "Signal Quality Error."; | 1802 | msg = "Signal Quality Error."; |
1307 | } | 1803 | } |
1308 | if (msg) | 1804 | if (msg && netif_msg_tx_err(lp)) |
1309 | printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status); | 1805 | printk(KERN_WARNING "%s: %s (%#x)\n", dev->name, msg, status); |
1310 | } | 1806 | } |
1311 | 1807 | ||
1808 | /* This handles TX complete events posted by the device | ||
1809 | * via interrupts. | ||
1810 | */ | ||
1312 | static void | 1811 | static void |
1313 | tc35815_txdone(struct net_device *dev) | 1812 | tc35815_txdone(struct net_device *dev) |
1314 | { | 1813 | { |
1315 | struct tc35815_local *lp = dev->priv; | 1814 | struct tc35815_local *lp = dev->priv; |
1316 | struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; | ||
1317 | struct TxFD *txfd; | 1815 | struct TxFD *txfd; |
1318 | unsigned int fdctl; | 1816 | unsigned int fdctl; |
1319 | int num_done = 0; | ||
1320 | 1817 | ||
1321 | txfd = &lp->tfd_base[lp->tfd_end]; | 1818 | txfd = &lp->tfd_base[lp->tfd_end]; |
1322 | while (lp->tfd_start != lp->tfd_end && | 1819 | while (lp->tfd_start != lp->tfd_end && |
@@ -1324,38 +1821,61 @@ tc35815_txdone(struct net_device *dev) | |||
1324 | int status = le32_to_cpu(txfd->fd.FDStat); | 1821 | int status = le32_to_cpu(txfd->fd.FDStat); |
1325 | struct sk_buff *skb; | 1822 | struct sk_buff *skb; |
1326 | unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext); | 1823 | unsigned long fdnext = le32_to_cpu(txfd->fd.FDNext); |
1824 | u32 fdsystem = le32_to_cpu(txfd->fd.FDSystem); | ||
1327 | 1825 | ||
1328 | if (tc35815_debug > 2) { | 1826 | if (netif_msg_tx_done(lp)) { |
1329 | printk("%s: complete TxFD.\n", dev->name); | 1827 | printk("%s: complete TxFD.\n", dev->name); |
1330 | dump_txfd(txfd); | 1828 | dump_txfd(txfd); |
1331 | } | 1829 | } |
1332 | tc35815_check_tx_stat(dev, status); | 1830 | tc35815_check_tx_stat(dev, status); |
1333 | 1831 | ||
1334 | skb = (struct sk_buff *)le32_to_cpu(txfd->fd.FDSystem); | 1832 | skb = fdsystem != 0xffffffff ? |
1833 | lp->tx_skbs[fdsystem].skb : NULL; | ||
1834 | #ifdef DEBUG | ||
1835 | if (lp->tx_skbs[lp->tfd_end].skb != skb) { | ||
1836 | printk("%s: tx_skbs mismatch.\n", dev->name); | ||
1837 | panic_queues(dev); | ||
1838 | } | ||
1839 | #else | ||
1840 | BUG_ON(lp->tx_skbs[lp->tfd_end].skb != skb); | ||
1841 | #endif | ||
1335 | if (skb) { | 1842 | if (skb) { |
1843 | lp->stats.tx_bytes += skb->len; | ||
1844 | pci_unmap_single(lp->pci_dev, lp->tx_skbs[lp->tfd_end].skb_dma, skb->len, PCI_DMA_TODEVICE); | ||
1845 | lp->tx_skbs[lp->tfd_end].skb = NULL; | ||
1846 | lp->tx_skbs[lp->tfd_end].skb_dma = 0; | ||
1847 | #ifdef TC35815_NAPI | ||
1336 | dev_kfree_skb_any(skb); | 1848 | dev_kfree_skb_any(skb); |
1849 | #else | ||
1850 | dev_kfree_skb_irq(skb); | ||
1851 | #endif | ||
1337 | } | 1852 | } |
1338 | txfd->fd.FDSystem = cpu_to_le32(0); | 1853 | txfd->fd.FDSystem = cpu_to_le32(0xffffffff); |
1339 | 1854 | ||
1340 | num_done++; | ||
1341 | lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM; | 1855 | lp->tfd_end = (lp->tfd_end + 1) % TX_FD_NUM; |
1342 | txfd = &lp->tfd_base[lp->tfd_end]; | 1856 | txfd = &lp->tfd_base[lp->tfd_end]; |
1343 | if ((fdnext & ~FD_Next_EOL) != virt_to_bus(txfd)) { | 1857 | #ifdef DEBUG |
1858 | if ((fdnext & ~FD_Next_EOL) != fd_virt_to_bus(lp, txfd)) { | ||
1344 | printk("%s: TxFD FDNext invalid.\n", dev->name); | 1859 | printk("%s: TxFD FDNext invalid.\n", dev->name); |
1345 | panic_queues(dev); | 1860 | panic_queues(dev); |
1346 | } | 1861 | } |
1862 | #endif | ||
1347 | if (fdnext & FD_Next_EOL) { | 1863 | if (fdnext & FD_Next_EOL) { |
1348 | /* DMA Transmitter has been stopping... */ | 1864 | /* DMA Transmitter has been stopping... */ |
1349 | if (lp->tfd_end != lp->tfd_start) { | 1865 | if (lp->tfd_end != lp->tfd_start) { |
1866 | struct tc35815_regs __iomem *tr = | ||
1867 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
1350 | int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM; | 1868 | int head = (lp->tfd_start + TX_FD_NUM - 1) % TX_FD_NUM; |
1351 | struct TxFD* txhead = &lp->tfd_base[head]; | 1869 | struct TxFD* txhead = &lp->tfd_base[head]; |
1352 | int qlen = (lp->tfd_start + TX_FD_NUM | 1870 | int qlen = (lp->tfd_start + TX_FD_NUM |
1353 | - lp->tfd_end) % TX_FD_NUM; | 1871 | - lp->tfd_end) % TX_FD_NUM; |
1354 | 1872 | ||
1873 | #ifdef DEBUG | ||
1355 | if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) { | 1874 | if (!(le32_to_cpu(txfd->fd.FDCtl) & FD_CownsFD)) { |
1356 | printk("%s: TxFD FDCtl invalid.\n", dev->name); | 1875 | printk("%s: TxFD FDCtl invalid.\n", dev->name); |
1357 | panic_queues(dev); | 1876 | panic_queues(dev); |
1358 | } | 1877 | } |
1878 | #endif | ||
1359 | /* log max queue length */ | 1879 | /* log max queue length */ |
1360 | if (lp->lstats.max_tx_qlen < qlen) | 1880 | if (lp->lstats.max_tx_qlen < qlen) |
1361 | lp->lstats.max_tx_qlen = qlen; | 1881 | lp->lstats.max_tx_qlen = qlen; |
@@ -1366,21 +1886,23 @@ tc35815_txdone(struct net_device *dev) | |||
1366 | #ifdef GATHER_TXINT | 1886 | #ifdef GATHER_TXINT |
1367 | txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); | 1887 | txhead->fd.FDCtl |= cpu_to_le32(FD_FrmOpt_IntTx); |
1368 | #endif | 1888 | #endif |
1369 | if (tc35815_debug > 2) { | 1889 | if (netif_msg_tx_queued(lp)) { |
1370 | printk("%s: start TxFD on queue.\n", | 1890 | printk("%s: start TxFD on queue.\n", |
1371 | dev->name); | 1891 | dev->name); |
1372 | dump_txfd(txfd); | 1892 | dump_txfd(txfd); |
1373 | } | 1893 | } |
1374 | tc_writel(virt_to_bus(txfd), &tr->TxFrmPtr); | 1894 | tc_writel(fd_virt_to_bus(lp, txfd), &tr->TxFrmPtr); |
1375 | } | 1895 | } |
1376 | break; | 1896 | break; |
1377 | } | 1897 | } |
1378 | } | 1898 | } |
1379 | 1899 | ||
1380 | if (num_done > 0 && lp->tbusy) { | 1900 | /* If we had stopped the queue due to a "tx full" |
1381 | lp->tbusy = 0; | 1901 | * condition, and space has now been made available, |
1382 | netif_start_queue(dev); | 1902 | * wake up the queue. |
1383 | } | 1903 | */ |
1904 | if (netif_queue_stopped(dev) && ! tc35815_tx_full(dev)) | ||
1905 | netif_wake_queue(dev); | ||
1384 | } | 1906 | } |
1385 | 1907 | ||
1386 | /* The inverse routine to tc35815_open(). */ | 1908 | /* The inverse routine to tc35815_open(). */ |
@@ -1388,18 +1910,18 @@ static int | |||
1388 | tc35815_close(struct net_device *dev) | 1910 | tc35815_close(struct net_device *dev) |
1389 | { | 1911 | { |
1390 | struct tc35815_local *lp = dev->priv; | 1912 | struct tc35815_local *lp = dev->priv; |
1391 | |||
1392 | lp->tbusy = 1; | ||
1393 | netif_stop_queue(dev); | 1913 | netif_stop_queue(dev); |
1394 | 1914 | ||
1395 | /* Flush the Tx and disable Rx here. */ | 1915 | /* Flush the Tx and disable Rx here. */ |
1396 | 1916 | ||
1917 | del_timer(&lp->timer); /* Kill if running */ | ||
1397 | tc35815_chip_reset(dev); | 1918 | tc35815_chip_reset(dev); |
1398 | free_irq(dev->irq, dev); | 1919 | free_irq(dev->irq, dev); |
1399 | 1920 | ||
1400 | tc35815_free_queues(dev); | 1921 | tc35815_free_queues(dev); |
1401 | 1922 | ||
1402 | return 0; | 1923 | return 0; |
1924 | |||
1403 | } | 1925 | } |
1404 | 1926 | ||
1405 | /* | 1927 | /* |
@@ -1409,29 +1931,29 @@ tc35815_close(struct net_device *dev) | |||
1409 | static struct net_device_stats *tc35815_get_stats(struct net_device *dev) | 1931 | static struct net_device_stats *tc35815_get_stats(struct net_device *dev) |
1410 | { | 1932 | { |
1411 | struct tc35815_local *lp = dev->priv; | 1933 | struct tc35815_local *lp = dev->priv; |
1412 | struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; | 1934 | struct tc35815_regs __iomem *tr = |
1413 | unsigned long flags; | 1935 | (struct tc35815_regs __iomem *)dev->base_addr; |
1414 | |||
1415 | if (netif_running(dev)) { | 1936 | if (netif_running(dev)) { |
1416 | spin_lock_irqsave(&lp->lock, flags); | ||
1417 | /* Update the statistics from the device registers. */ | 1937 | /* Update the statistics from the device registers. */ |
1418 | lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); | 1938 | lp->stats.rx_missed_errors = tc_readl(&tr->Miss_Cnt); |
1419 | spin_unlock_irqrestore(&lp->lock, flags); | ||
1420 | } | 1939 | } |
1421 | 1940 | ||
1422 | return &lp->stats; | 1941 | return &lp->stats; |
1423 | } | 1942 | } |
1424 | 1943 | ||
1425 | static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned char *addr) | 1944 | static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned char *addr) |
1426 | { | 1945 | { |
1946 | struct tc35815_local *lp = dev->priv; | ||
1947 | struct tc35815_regs __iomem *tr = | ||
1948 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
1427 | int cam_index = index * 6; | 1949 | int cam_index = index * 6; |
1428 | unsigned long cam_data; | 1950 | u32 cam_data; |
1429 | unsigned long saved_addr; | 1951 | u32 saved_addr; |
1430 | saved_addr = tc_readl(&tr->CAM_Adr); | 1952 | saved_addr = tc_readl(&tr->CAM_Adr); |
1431 | 1953 | ||
1432 | if (tc35815_debug > 1) { | 1954 | if (netif_msg_hw(lp)) { |
1433 | int i; | 1955 | int i; |
1434 | printk(KERN_DEBUG "%s: CAM %d:", cardname, index); | 1956 | printk(KERN_DEBUG "%s: CAM %d:", dev->name, index); |
1435 | for (i = 0; i < 6; i++) | 1957 | for (i = 0; i < 6; i++) |
1436 | printk(" %02x", addr[i]); | 1958 | printk(" %02x", addr[i]); |
1437 | printk("\n"); | 1959 | printk("\n"); |
@@ -1458,14 +1980,6 @@ static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned c | |||
1458 | tc_writel(cam_data, &tr->CAM_Data); | 1980 | tc_writel(cam_data, &tr->CAM_Data); |
1459 | } | 1981 | } |
1460 | 1982 | ||
1461 | if (tc35815_debug > 2) { | ||
1462 | int i; | ||
1463 | for (i = cam_index / 4; i < cam_index / 4 + 2; i++) { | ||
1464 | tc_writel(i * 4, &tr->CAM_Adr); | ||
1465 | printk("CAM 0x%x: %08lx", | ||
1466 | i * 4, tc_readl(&tr->CAM_Data)); | ||
1467 | } | ||
1468 | } | ||
1469 | tc_writel(saved_addr, &tr->CAM_Adr); | 1983 | tc_writel(saved_addr, &tr->CAM_Adr); |
1470 | } | 1984 | } |
1471 | 1985 | ||
@@ -1480,10 +1994,19 @@ static void tc35815_set_cam_entry(struct tc35815_regs *tr, int index, unsigned c | |||
1480 | static void | 1994 | static void |
1481 | tc35815_set_multicast_list(struct net_device *dev) | 1995 | tc35815_set_multicast_list(struct net_device *dev) |
1482 | { | 1996 | { |
1483 | struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; | 1997 | struct tc35815_regs __iomem *tr = |
1998 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
1484 | 1999 | ||
1485 | if (dev->flags&IFF_PROMISC) | 2000 | if (dev->flags&IFF_PROMISC) |
1486 | { | 2001 | { |
2002 | #ifdef WORKAROUND_100HALF_PROMISC | ||
2003 | /* With some (all?) 100MHalf HUB, controller will hang | ||
2004 | * if we enabled promiscuous mode before linkup... */ | ||
2005 | struct tc35815_local *lp = dev->priv; | ||
2006 | int pid = lp->phy_addr; | ||
2007 | if (!(tc_mdio_read(dev, pid, MII_BMSR) & BMSR_LSTATUS)) | ||
2008 | return; | ||
2009 | #endif | ||
1487 | /* Enable promiscuous mode */ | 2010 | /* Enable promiscuous mode */ |
1488 | tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); | 2011 | tc_writel(CAM_CompEn | CAM_BroadAcc | CAM_GroupAcc | CAM_StationAcc, &tr->CAM_Ctl); |
1489 | } | 2012 | } |
@@ -1505,7 +2028,7 @@ tc35815_set_multicast_list(struct net_device *dev) | |||
1505 | if (!cur_addr) | 2028 | if (!cur_addr) |
1506 | break; | 2029 | break; |
1507 | /* entry 0,1 is reserved. */ | 2030 | /* entry 0,1 is reserved. */ |
1508 | tc35815_set_cam_entry(tr, i + 2, cur_addr->dmi_addr); | 2031 | tc35815_set_cam_entry(dev, i + 2, cur_addr->dmi_addr); |
1509 | ena_bits |= CAM_Ena_Bit(i + 2); | 2032 | ena_bits |= CAM_Ena_Bit(i + 2); |
1510 | } | 2033 | } |
1511 | tc_writel(ena_bits, &tr->CAM_Ena); | 2034 | tc_writel(ena_bits, &tr->CAM_Ena); |
@@ -1517,122 +2040,753 @@ tc35815_set_multicast_list(struct net_device *dev) | |||
1517 | } | 2040 | } |
1518 | } | 2041 | } |
1519 | 2042 | ||
1520 | static unsigned long tc_phy_read(struct net_device *dev, struct tc35815_regs *tr, int phy, int phy_reg) | 2043 | static void tc35815_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
1521 | { | 2044 | { |
1522 | struct tc35815_local *lp = dev->priv; | 2045 | struct tc35815_local *lp = dev->priv; |
1523 | unsigned long data; | 2046 | strcpy(info->driver, MODNAME); |
1524 | unsigned long flags; | 2047 | strcpy(info->version, DRV_VERSION); |
2048 | strcpy(info->bus_info, pci_name(lp->pci_dev)); | ||
2049 | } | ||
1525 | 2050 | ||
1526 | spin_lock_irqsave(&lp->lock, flags); | 2051 | static int tc35815_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
2052 | { | ||
2053 | struct tc35815_local *lp = dev->priv; | ||
2054 | spin_lock_irq(&lp->lock); | ||
2055 | mii_ethtool_gset(&lp->mii, cmd); | ||
2056 | spin_unlock_irq(&lp->lock); | ||
2057 | return 0; | ||
2058 | } | ||
1527 | 2059 | ||
1528 | tc_writel(MD_CA_Busy | (phy << 5) | phy_reg, &tr->MD_CA); | 2060 | static int tc35815_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
2061 | { | ||
2062 | struct tc35815_local *lp = dev->priv; | ||
2063 | int rc; | ||
2064 | #if 1 /* use our negotiation method... */ | ||
2065 | /* Verify the settings we care about. */ | ||
2066 | if (cmd->autoneg != AUTONEG_ENABLE && | ||
2067 | cmd->autoneg != AUTONEG_DISABLE) | ||
2068 | return -EINVAL; | ||
2069 | if (cmd->autoneg == AUTONEG_DISABLE && | ||
2070 | ((cmd->speed != SPEED_100 && | ||
2071 | cmd->speed != SPEED_10) || | ||
2072 | (cmd->duplex != DUPLEX_HALF && | ||
2073 | cmd->duplex != DUPLEX_FULL))) | ||
2074 | return -EINVAL; | ||
2075 | |||
2076 | /* Ok, do it to it. */ | ||
2077 | spin_lock_irq(&lp->lock); | ||
2078 | del_timer(&lp->timer); | ||
2079 | tc35815_start_auto_negotiation(dev, cmd); | ||
2080 | spin_unlock_irq(&lp->lock); | ||
2081 | rc = 0; | ||
2082 | #else | ||
2083 | spin_lock_irq(&lp->lock); | ||
2084 | rc = mii_ethtool_sset(&lp->mii, cmd); | ||
2085 | spin_unlock_irq(&lp->lock); | ||
2086 | #endif | ||
2087 | return rc; | ||
2088 | } | ||
2089 | |||
2090 | static int tc35815_nway_reset(struct net_device *dev) | ||
2091 | { | ||
2092 | struct tc35815_local *lp = dev->priv; | ||
2093 | int rc; | ||
2094 | spin_lock_irq(&lp->lock); | ||
2095 | rc = mii_nway_restart(&lp->mii); | ||
2096 | spin_unlock_irq(&lp->lock); | ||
2097 | return rc; | ||
2098 | } | ||
2099 | |||
2100 | static u32 tc35815_get_link(struct net_device *dev) | ||
2101 | { | ||
2102 | struct tc35815_local *lp = dev->priv; | ||
2103 | int rc; | ||
2104 | spin_lock_irq(&lp->lock); | ||
2105 | rc = mii_link_ok(&lp->mii); | ||
2106 | spin_unlock_irq(&lp->lock); | ||
2107 | return rc; | ||
2108 | } | ||
2109 | |||
2110 | static u32 tc35815_get_msglevel(struct net_device *dev) | ||
2111 | { | ||
2112 | struct tc35815_local *lp = dev->priv; | ||
2113 | return lp->msg_enable; | ||
2114 | } | ||
2115 | |||
2116 | static void tc35815_set_msglevel(struct net_device *dev, u32 datum) | ||
2117 | { | ||
2118 | struct tc35815_local *lp = dev->priv; | ||
2119 | lp->msg_enable = datum; | ||
2120 | } | ||
2121 | |||
2122 | static int tc35815_get_stats_count(struct net_device *dev) | ||
2123 | { | ||
2124 | struct tc35815_local *lp = dev->priv; | ||
2125 | return sizeof(lp->lstats) / sizeof(int); | ||
2126 | } | ||
2127 | |||
2128 | static void tc35815_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) | ||
2129 | { | ||
2130 | struct tc35815_local *lp = dev->priv; | ||
2131 | data[0] = lp->lstats.max_tx_qlen; | ||
2132 | data[1] = lp->lstats.tx_ints; | ||
2133 | data[2] = lp->lstats.rx_ints; | ||
2134 | data[3] = lp->lstats.tx_underrun; | ||
2135 | } | ||
2136 | |||
2137 | static struct { | ||
2138 | const char str[ETH_GSTRING_LEN]; | ||
2139 | } ethtool_stats_keys[] = { | ||
2140 | { "max_tx_qlen" }, | ||
2141 | { "tx_ints" }, | ||
2142 | { "rx_ints" }, | ||
2143 | { "tx_underrun" }, | ||
2144 | }; | ||
2145 | |||
2146 | static void tc35815_get_strings(struct net_device *dev, u32 stringset, u8 *data) | ||
2147 | { | ||
2148 | memcpy(data, ethtool_stats_keys, sizeof(ethtool_stats_keys)); | ||
2149 | } | ||
2150 | |||
2151 | static const struct ethtool_ops tc35815_ethtool_ops = { | ||
2152 | .get_drvinfo = tc35815_get_drvinfo, | ||
2153 | .get_settings = tc35815_get_settings, | ||
2154 | .set_settings = tc35815_set_settings, | ||
2155 | .nway_reset = tc35815_nway_reset, | ||
2156 | .get_link = tc35815_get_link, | ||
2157 | .get_msglevel = tc35815_get_msglevel, | ||
2158 | .set_msglevel = tc35815_set_msglevel, | ||
2159 | .get_strings = tc35815_get_strings, | ||
2160 | .get_stats_count = tc35815_get_stats_count, | ||
2161 | .get_ethtool_stats = tc35815_get_ethtool_stats, | ||
2162 | .get_perm_addr = ethtool_op_get_perm_addr, | ||
2163 | }; | ||
2164 | |||
2165 | static int tc35815_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
2166 | { | ||
2167 | struct tc35815_local *lp = dev->priv; | ||
2168 | int rc; | ||
2169 | |||
2170 | if (!netif_running(dev)) | ||
2171 | return -EINVAL; | ||
2172 | |||
2173 | spin_lock_irq(&lp->lock); | ||
2174 | rc = generic_mii_ioctl(&lp->mii, if_mii(rq), cmd, NULL); | ||
2175 | spin_unlock_irq(&lp->lock); | ||
2176 | |||
2177 | return rc; | ||
2178 | } | ||
2179 | |||
2180 | static int tc_mdio_read(struct net_device *dev, int phy_id, int location) | ||
2181 | { | ||
2182 | struct tc35815_regs __iomem *tr = | ||
2183 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
2184 | u32 data; | ||
2185 | tc_writel(MD_CA_Busy | (phy_id << 5) | location, &tr->MD_CA); | ||
1529 | while (tc_readl(&tr->MD_CA) & MD_CA_Busy) | 2186 | while (tc_readl(&tr->MD_CA) & MD_CA_Busy) |
1530 | ; | 2187 | ; |
1531 | data = tc_readl(&tr->MD_Data); | 2188 | data = tc_readl(&tr->MD_Data); |
1532 | spin_unlock_irqrestore(&lp->lock, flags); | 2189 | return data & 0xffff; |
1533 | return data; | 2190 | } |
2191 | |||
2192 | static void tc_mdio_write(struct net_device *dev, int phy_id, int location, | ||
2193 | int val) | ||
2194 | { | ||
2195 | struct tc35815_regs __iomem *tr = | ||
2196 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
2197 | tc_writel(val, &tr->MD_Data); | ||
2198 | tc_writel(MD_CA_Busy | MD_CA_Wr | (phy_id << 5) | location, &tr->MD_CA); | ||
2199 | while (tc_readl(&tr->MD_CA) & MD_CA_Busy) | ||
2200 | ; | ||
1534 | } | 2201 | } |
1535 | 2202 | ||
1536 | static void tc_phy_write(struct net_device *dev, unsigned long d, struct tc35815_regs *tr, int phy, int phy_reg) | 2203 | /* Auto negotiation. The scheme is very simple. We have a timer routine |
2204 | * that keeps watching the auto negotiation process as it progresses. | ||
2205 | * The DP83840 is first told to start doing it's thing, we set up the time | ||
2206 | * and place the timer state machine in it's initial state. | ||
2207 | * | ||
2208 | * Here the timer peeks at the DP83840 status registers at each click to see | ||
2209 | * if the auto negotiation has completed, we assume here that the DP83840 PHY | ||
2210 | * will time out at some point and just tell us what (didn't) happen. For | ||
2211 | * complete coverage we only allow so many of the ticks at this level to run, | ||
2212 | * when this has expired we print a warning message and try another strategy. | ||
2213 | * This "other" strategy is to force the interface into various speed/duplex | ||
2214 | * configurations and we stop when we see a link-up condition before the | ||
2215 | * maximum number of "peek" ticks have occurred. | ||
2216 | * | ||
2217 | * Once a valid link status has been detected we configure the BigMAC and | ||
2218 | * the rest of the Happy Meal to speak the most efficient protocol we could | ||
2219 | * get a clean link for. The priority for link configurations, highest first | ||
2220 | * is: | ||
2221 | * 100 Base-T Full Duplex | ||
2222 | * 100 Base-T Half Duplex | ||
2223 | * 10 Base-T Full Duplex | ||
2224 | * 10 Base-T Half Duplex | ||
2225 | * | ||
2226 | * We start a new timer now, after a successful auto negotiation status has | ||
2227 | * been detected. This timer just waits for the link-up bit to get set in | ||
2228 | * the BMCR of the DP83840. When this occurs we print a kernel log message | ||
2229 | * describing the link type in use and the fact that it is up. | ||
2230 | * | ||
2231 | * If a fatal error of some sort is signalled and detected in the interrupt | ||
2232 | * service routine, and the chip is reset, or the link is ifconfig'd down | ||
2233 | * and then back up, this entire process repeats itself all over again. | ||
2234 | */ | ||
2235 | /* Note: Above comments are come from sunhme driver. */ | ||
2236 | |||
2237 | static int tc35815_try_next_permutation(struct net_device *dev) | ||
1537 | { | 2238 | { |
1538 | struct tc35815_local *lp = dev->priv; | 2239 | struct tc35815_local *lp = dev->priv; |
1539 | unsigned long flags; | 2240 | int pid = lp->phy_addr; |
2241 | unsigned short bmcr; | ||
1540 | 2242 | ||
1541 | spin_lock_irqsave(&lp->lock, flags); | 2243 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); |
1542 | 2244 | ||
1543 | tc_writel(d, &tr->MD_Data); | 2245 | /* Downgrade from full to half duplex. Only possible via ethtool. */ |
1544 | tc_writel(MD_CA_Busy | MD_CA_Wr | (phy << 5) | phy_reg, &tr->MD_CA); | 2246 | if (bmcr & BMCR_FULLDPLX) { |
1545 | while (tc_readl(&tr->MD_CA) & MD_CA_Busy) | 2247 | bmcr &= ~BMCR_FULLDPLX; |
1546 | ; | 2248 | printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr); |
1547 | spin_unlock_irqrestore(&lp->lock, flags); | 2249 | tc_mdio_write(dev, pid, MII_BMCR, bmcr); |
2250 | return 0; | ||
2251 | } | ||
2252 | |||
2253 | /* Downgrade from 100 to 10. */ | ||
2254 | if (bmcr & BMCR_SPEED100) { | ||
2255 | bmcr &= ~BMCR_SPEED100; | ||
2256 | printk(KERN_DEBUG "%s: try next permutation (BMCR %x)\n", dev->name, bmcr); | ||
2257 | tc_mdio_write(dev, pid, MII_BMCR, bmcr); | ||
2258 | return 0; | ||
2259 | } | ||
2260 | |||
2261 | /* We've tried everything. */ | ||
2262 | return -1; | ||
1548 | } | 2263 | } |
1549 | 2264 | ||
1550 | static void tc35815_phy_chip_init(struct net_device *dev) | 2265 | static void |
2266 | tc35815_display_link_mode(struct net_device *dev) | ||
1551 | { | 2267 | { |
1552 | struct tc35815_local *lp = dev->priv; | 2268 | struct tc35815_local *lp = dev->priv; |
1553 | struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; | 2269 | int pid = lp->phy_addr; |
1554 | static int first = 1; | 2270 | unsigned short lpa, bmcr; |
1555 | unsigned short ctl; | 2271 | char *speed = "", *duplex = ""; |
1556 | 2272 | ||
1557 | if (first) { | 2273 | lpa = tc_mdio_read(dev, pid, MII_LPA); |
1558 | unsigned short id0, id1; | 2274 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); |
1559 | int count; | 2275 | if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL))) |
1560 | first = 0; | 2276 | speed = "100Mb/s"; |
1561 | 2277 | else | |
1562 | /* first data written to the PHY will be an ID number */ | 2278 | speed = "10Mb/s"; |
1563 | tc_phy_write(dev, 0, tr, 0, MII_CONTROL); /* ID:0 */ | 2279 | if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL))) |
1564 | #if 0 | 2280 | duplex = "Full Duplex"; |
1565 | tc_phy_write(dev, MIICNTL_RESET, tr, 0, MII_CONTROL); | 2281 | else |
1566 | printk(KERN_INFO "%s: Resetting PHY...", dev->name); | 2282 | duplex = "Half Duplex"; |
1567 | while (tc_phy_read(dev, tr, 0, MII_CONTROL) & MIICNTL_RESET) | 2283 | |
1568 | ; | 2284 | if (netif_msg_link(lp)) |
1569 | printk("\n"); | 2285 | printk(KERN_INFO "%s: Link is up at %s, %s.\n", |
1570 | tc_phy_write(dev, MIICNTL_AUTO|MIICNTL_SPEED|MIICNTL_FDX, tr, 0, | 2286 | dev->name, speed, duplex); |
1571 | MII_CONTROL); | 2287 | printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n", |
1572 | #endif | 2288 | dev->name, |
1573 | id0 = tc_phy_read(dev, tr, 0, MII_PHY_ID0); | 2289 | bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa); |
1574 | id1 = tc_phy_read(dev, tr, 0, MII_PHY_ID1); | 2290 | } |
1575 | printk(KERN_DEBUG "%s: PHY ID %04x %04x\n", dev->name, | 2291 | |
1576 | id0, id1); | 2292 | static void tc35815_display_forced_link_mode(struct net_device *dev) |
1577 | if (lp->option & TC35815_OPT_10M) { | 2293 | { |
1578 | lp->linkspeed = 10; | 2294 | struct tc35815_local *lp = dev->priv; |
1579 | lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; | 2295 | int pid = lp->phy_addr; |
1580 | } else if (lp->option & TC35815_OPT_100M) { | 2296 | unsigned short bmcr; |
1581 | lp->linkspeed = 100; | 2297 | char *speed = "", *duplex = ""; |
1582 | lp->fullduplex = (lp->option & TC35815_OPT_FULLDUP) != 0; | 2298 | |
2299 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); | ||
2300 | if (bmcr & BMCR_SPEED100) | ||
2301 | speed = "100Mb/s"; | ||
2302 | else | ||
2303 | speed = "10Mb/s"; | ||
2304 | if (bmcr & BMCR_FULLDPLX) | ||
2305 | duplex = "Full Duplex.\n"; | ||
2306 | else | ||
2307 | duplex = "Half Duplex.\n"; | ||
2308 | |||
2309 | if (netif_msg_link(lp)) | ||
2310 | printk(KERN_INFO "%s: Link has been forced up at %s, %s", | ||
2311 | dev->name, speed, duplex); | ||
2312 | } | ||
2313 | |||
2314 | static void tc35815_set_link_modes(struct net_device *dev) | ||
2315 | { | ||
2316 | struct tc35815_local *lp = dev->priv; | ||
2317 | struct tc35815_regs __iomem *tr = | ||
2318 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
2319 | int pid = lp->phy_addr; | ||
2320 | unsigned short bmcr, lpa; | ||
2321 | int speed; | ||
2322 | |||
2323 | if (lp->timer_state == arbwait) { | ||
2324 | lpa = tc_mdio_read(dev, pid, MII_LPA); | ||
2325 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); | ||
2326 | printk(KERN_DEBUG "%s: MII BMCR %04x BMSR %04x LPA %04x\n", | ||
2327 | dev->name, | ||
2328 | bmcr, tc_mdio_read(dev, pid, MII_BMSR), lpa); | ||
2329 | if (!(lpa & (LPA_10HALF | LPA_10FULL | | ||
2330 | LPA_100HALF | LPA_100FULL))) { | ||
2331 | /* fall back to 10HALF */ | ||
2332 | printk(KERN_INFO "%s: bad ability %04x - falling back to 10HD.\n", | ||
2333 | dev->name, lpa); | ||
2334 | lpa = LPA_10HALF; | ||
2335 | } | ||
2336 | if (options.duplex ? (bmcr & BMCR_FULLDPLX) : (lpa & (LPA_100FULL | LPA_10FULL))) | ||
2337 | lp->fullduplex = 1; | ||
2338 | else | ||
2339 | lp->fullduplex = 0; | ||
2340 | if (options.speed ? (bmcr & BMCR_SPEED100) : (lpa & (LPA_100HALF | LPA_100FULL))) | ||
2341 | speed = 100; | ||
2342 | else | ||
2343 | speed = 10; | ||
2344 | } else { | ||
2345 | /* Forcing a link mode. */ | ||
2346 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); | ||
2347 | if (bmcr & BMCR_FULLDPLX) | ||
2348 | lp->fullduplex = 1; | ||
2349 | else | ||
2350 | lp->fullduplex = 0; | ||
2351 | if (bmcr & BMCR_SPEED100) | ||
2352 | speed = 100; | ||
2353 | else | ||
2354 | speed = 10; | ||
2355 | } | ||
2356 | |||
2357 | tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_HaltReq, &tr->MAC_Ctl); | ||
2358 | if (lp->fullduplex) { | ||
2359 | tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); | ||
2360 | } else { | ||
2361 | tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_FullDup, &tr->MAC_Ctl); | ||
2362 | } | ||
2363 | tc_writel(tc_readl(&tr->MAC_Ctl) & ~MAC_HaltReq, &tr->MAC_Ctl); | ||
2364 | |||
2365 | /* TX4939 PCFG.SPEEDn bit will be changed on NETDEV_CHANGE event. */ | ||
2366 | |||
2367 | #ifndef NO_CHECK_CARRIER | ||
2368 | /* TX4939 does not have EnLCarr */ | ||
2369 | if (lp->boardtype != TC35815_TX4939) { | ||
2370 | #ifdef WORKAROUND_LOSTCAR | ||
2371 | /* WORKAROUND: enable LostCrS only if half duplex operation */ | ||
2372 | if (!lp->fullduplex && lp->boardtype != TC35815_TX4939) | ||
2373 | tc_writel(tc_readl(&tr->Tx_Ctl) | Tx_EnLCarr, &tr->Tx_Ctl); | ||
2374 | #endif | ||
2375 | } | ||
2376 | #endif | ||
2377 | lp->mii.full_duplex = lp->fullduplex; | ||
2378 | } | ||
2379 | |||
2380 | static void tc35815_timer(unsigned long data) | ||
2381 | { | ||
2382 | struct net_device *dev = (struct net_device *)data; | ||
2383 | struct tc35815_local *lp = dev->priv; | ||
2384 | int pid = lp->phy_addr; | ||
2385 | unsigned short bmsr, bmcr, lpa; | ||
2386 | int restart_timer = 0; | ||
2387 | |||
2388 | spin_lock_irq(&lp->lock); | ||
2389 | |||
2390 | lp->timer_ticks++; | ||
2391 | switch (lp->timer_state) { | ||
2392 | case arbwait: | ||
2393 | /* | ||
2394 | * Only allow for 5 ticks, thats 10 seconds and much too | ||
2395 | * long to wait for arbitration to complete. | ||
2396 | */ | ||
2397 | /* TC35815 need more times... */ | ||
2398 | if (lp->timer_ticks >= 10) { | ||
2399 | /* Enter force mode. */ | ||
2400 | if (!options.doforce) { | ||
2401 | printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," | ||
2402 | " cable probblem?\n", dev->name); | ||
2403 | /* Try to restart the adaptor. */ | ||
2404 | tc35815_restart(dev); | ||
2405 | goto out; | ||
2406 | } | ||
2407 | printk(KERN_NOTICE "%s: Auto-Negotiation unsuccessful," | ||
2408 | " trying force link mode\n", dev->name); | ||
2409 | printk(KERN_DEBUG "%s: BMCR %x BMSR %x\n", dev->name, | ||
2410 | tc_mdio_read(dev, pid, MII_BMCR), | ||
2411 | tc_mdio_read(dev, pid, MII_BMSR)); | ||
2412 | bmcr = BMCR_SPEED100; | ||
2413 | tc_mdio_write(dev, pid, MII_BMCR, bmcr); | ||
2414 | |||
2415 | /* | ||
2416 | * OK, seems we need do disable the transceiver | ||
2417 | * for the first tick to make sure we get an | ||
2418 | * accurate link state at the second tick. | ||
2419 | */ | ||
2420 | |||
2421 | lp->timer_state = ltrywait; | ||
2422 | lp->timer_ticks = 0; | ||
2423 | restart_timer = 1; | ||
1583 | } else { | 2424 | } else { |
1584 | /* auto negotiation */ | 2425 | /* Anything interesting happen? */ |
1585 | unsigned long neg_result; | 2426 | bmsr = tc_mdio_read(dev, pid, MII_BMSR); |
1586 | tc_phy_write(dev, MIICNTL_AUTO | MIICNTL_RST_AUTO, tr, 0, MII_CONTROL); | 2427 | if (bmsr & BMSR_ANEGCOMPLETE) { |
1587 | printk(KERN_INFO "%s: Auto Negotiation...", dev->name); | 2428 | /* Just what we've been waiting for... */ |
1588 | count = 0; | 2429 | tc35815_set_link_modes(dev); |
1589 | while (!(tc_phy_read(dev, tr, 0, MII_STATUS) & MIISTAT_AUTO_DONE)) { | 2430 | |
1590 | if (count++ > 5000) { | 2431 | /* |
1591 | printk(" failed. Assume 10Mbps\n"); | 2432 | * Success, at least so far, advance our state |
1592 | lp->linkspeed = 10; | 2433 | * engine. |
1593 | lp->fullduplex = 0; | 2434 | */ |
1594 | goto done; | 2435 | lp->timer_state = lupwait; |
2436 | restart_timer = 1; | ||
2437 | } else { | ||
2438 | restart_timer = 1; | ||
2439 | } | ||
2440 | } | ||
2441 | break; | ||
2442 | |||
2443 | case lupwait: | ||
2444 | /* | ||
2445 | * Auto negotiation was successful and we are awaiting a | ||
2446 | * link up status. I have decided to let this timer run | ||
2447 | * forever until some sort of error is signalled, reporting | ||
2448 | * a message to the user at 10 second intervals. | ||
2449 | */ | ||
2450 | bmsr = tc_mdio_read(dev, pid, MII_BMSR); | ||
2451 | if (bmsr & BMSR_LSTATUS) { | ||
2452 | /* | ||
2453 | * Wheee, it's up, display the link mode in use and put | ||
2454 | * the timer to sleep. | ||
2455 | */ | ||
2456 | tc35815_display_link_mode(dev); | ||
2457 | netif_carrier_on(dev); | ||
2458 | #ifdef WORKAROUND_100HALF_PROMISC | ||
2459 | /* delayed promiscuous enabling */ | ||
2460 | if (dev->flags & IFF_PROMISC) | ||
2461 | tc35815_set_multicast_list(dev); | ||
2462 | #endif | ||
2463 | #if 1 | ||
2464 | lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA); | ||
2465 | lp->timer_state = lcheck; | ||
2466 | restart_timer = 1; | ||
2467 | #else | ||
2468 | lp->timer_state = asleep; | ||
2469 | restart_timer = 0; | ||
2470 | #endif | ||
2471 | } else { | ||
2472 | if (lp->timer_ticks >= 10) { | ||
2473 | printk(KERN_NOTICE "%s: Auto negotiation successful, link still " | ||
2474 | "not completely up.\n", dev->name); | ||
2475 | lp->timer_ticks = 0; | ||
2476 | restart_timer = 1; | ||
2477 | } else { | ||
2478 | restart_timer = 1; | ||
2479 | } | ||
2480 | } | ||
2481 | break; | ||
2482 | |||
2483 | case ltrywait: | ||
2484 | /* | ||
2485 | * Making the timeout here too long can make it take | ||
2486 | * annoyingly long to attempt all of the link mode | ||
2487 | * permutations, but then again this is essentially | ||
2488 | * error recovery code for the most part. | ||
2489 | */ | ||
2490 | bmsr = tc_mdio_read(dev, pid, MII_BMSR); | ||
2491 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); | ||
2492 | if (lp->timer_ticks == 1) { | ||
2493 | /* | ||
2494 | * Re-enable transceiver, we'll re-enable the | ||
2495 | * transceiver next tick, then check link state | ||
2496 | * on the following tick. | ||
2497 | */ | ||
2498 | restart_timer = 1; | ||
2499 | break; | ||
2500 | } | ||
2501 | if (lp->timer_ticks == 2) { | ||
2502 | restart_timer = 1; | ||
2503 | break; | ||
2504 | } | ||
2505 | if (bmsr & BMSR_LSTATUS) { | ||
2506 | /* Force mode selection success. */ | ||
2507 | tc35815_display_forced_link_mode(dev); | ||
2508 | netif_carrier_on(dev); | ||
2509 | tc35815_set_link_modes(dev); | ||
2510 | #ifdef WORKAROUND_100HALF_PROMISC | ||
2511 | /* delayed promiscuous enabling */ | ||
2512 | if (dev->flags & IFF_PROMISC) | ||
2513 | tc35815_set_multicast_list(dev); | ||
2514 | #endif | ||
2515 | #if 1 | ||
2516 | lp->saved_lpa = tc_mdio_read(dev, pid, MII_LPA); | ||
2517 | lp->timer_state = lcheck; | ||
2518 | restart_timer = 1; | ||
2519 | #else | ||
2520 | lp->timer_state = asleep; | ||
2521 | restart_timer = 0; | ||
2522 | #endif | ||
2523 | } else { | ||
2524 | if (lp->timer_ticks >= 4) { /* 6 seconds or so... */ | ||
2525 | int ret; | ||
2526 | |||
2527 | ret = tc35815_try_next_permutation(dev); | ||
2528 | if (ret == -1) { | ||
2529 | /* | ||
2530 | * Aieee, tried them all, reset the | ||
2531 | * chip and try all over again. | ||
2532 | */ | ||
2533 | printk(KERN_NOTICE "%s: Link down, " | ||
2534 | "cable problem?\n", | ||
2535 | dev->name); | ||
2536 | |||
2537 | /* Try to restart the adaptor. */ | ||
2538 | tc35815_restart(dev); | ||
2539 | goto out; | ||
1595 | } | 2540 | } |
1596 | if (count % 512 == 0) | 2541 | lp->timer_ticks = 0; |
1597 | printk("."); | 2542 | restart_timer = 1; |
1598 | mdelay(1); | 2543 | } else { |
2544 | restart_timer = 1; | ||
2545 | } | ||
2546 | } | ||
2547 | break; | ||
2548 | |||
2549 | case lcheck: | ||
2550 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); | ||
2551 | lpa = tc_mdio_read(dev, pid, MII_LPA); | ||
2552 | if (bmcr & (BMCR_PDOWN | BMCR_ISOLATE | BMCR_RESET)) { | ||
2553 | printk(KERN_ERR "%s: PHY down? (BMCR %x)\n", dev->name, | ||
2554 | bmcr); | ||
2555 | } else if ((lp->saved_lpa ^ lpa) & | ||
2556 | (LPA_100FULL|LPA_100HALF|LPA_10FULL|LPA_10HALF)) { | ||
2557 | printk(KERN_NOTICE "%s: link status changed" | ||
2558 | " (BMCR %x LPA %x->%x)\n", dev->name, | ||
2559 | bmcr, lp->saved_lpa, lpa); | ||
2560 | } else { | ||
2561 | /* go on */ | ||
2562 | restart_timer = 1; | ||
2563 | break; | ||
2564 | } | ||
2565 | /* Try to restart the adaptor. */ | ||
2566 | tc35815_restart(dev); | ||
2567 | goto out; | ||
2568 | |||
2569 | case asleep: | ||
2570 | default: | ||
2571 | /* Can't happens.... */ | ||
2572 | printk(KERN_ERR "%s: Aieee, link timer is asleep but we got " | ||
2573 | "one anyways!\n", dev->name); | ||
2574 | restart_timer = 0; | ||
2575 | lp->timer_ticks = 0; | ||
2576 | lp->timer_state = asleep; /* foo on you */ | ||
2577 | break; | ||
2578 | } | ||
2579 | |||
2580 | if (restart_timer) { | ||
2581 | lp->timer.expires = jiffies + msecs_to_jiffies(1200); | ||
2582 | add_timer(&lp->timer); | ||
2583 | } | ||
2584 | out: | ||
2585 | spin_unlock_irq(&lp->lock); | ||
2586 | } | ||
2587 | |||
2588 | static void tc35815_start_auto_negotiation(struct net_device *dev, | ||
2589 | struct ethtool_cmd *ep) | ||
2590 | { | ||
2591 | struct tc35815_local *lp = dev->priv; | ||
2592 | int pid = lp->phy_addr; | ||
2593 | unsigned short bmsr, bmcr, advertize; | ||
2594 | int timeout; | ||
2595 | |||
2596 | netif_carrier_off(dev); | ||
2597 | bmsr = tc_mdio_read(dev, pid, MII_BMSR); | ||
2598 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); | ||
2599 | advertize = tc_mdio_read(dev, pid, MII_ADVERTISE); | ||
2600 | |||
2601 | if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { | ||
2602 | if (options.speed || options.duplex) { | ||
2603 | /* Advertise only specified configuration. */ | ||
2604 | advertize &= ~(ADVERTISE_10HALF | | ||
2605 | ADVERTISE_10FULL | | ||
2606 | ADVERTISE_100HALF | | ||
2607 | ADVERTISE_100FULL); | ||
2608 | if (options.speed != 10) { | ||
2609 | if (options.duplex != 1) | ||
2610 | advertize |= ADVERTISE_100FULL; | ||
2611 | if (options.duplex != 2) | ||
2612 | advertize |= ADVERTISE_100HALF; | ||
2613 | } | ||
2614 | if (options.speed != 100) { | ||
2615 | if (options.duplex != 1) | ||
2616 | advertize |= ADVERTISE_10FULL; | ||
2617 | if (options.duplex != 2) | ||
2618 | advertize |= ADVERTISE_10HALF; | ||
1599 | } | 2619 | } |
1600 | printk(" done.\n"); | 2620 | if (options.speed == 100) |
1601 | neg_result = tc_phy_read(dev, tr, 0, MII_ANLPAR); | 2621 | bmcr |= BMCR_SPEED100; |
1602 | if (neg_result & (MII_AN_TX_FDX | MII_AN_TX_HDX)) | 2622 | else if (options.speed == 10) |
1603 | lp->linkspeed = 100; | 2623 | bmcr &= ~BMCR_SPEED100; |
2624 | if (options.duplex == 2) | ||
2625 | bmcr |= BMCR_FULLDPLX; | ||
2626 | else if (options.duplex == 1) | ||
2627 | bmcr &= ~BMCR_FULLDPLX; | ||
2628 | } else { | ||
2629 | /* Advertise everything we can support. */ | ||
2630 | if (bmsr & BMSR_10HALF) | ||
2631 | advertize |= ADVERTISE_10HALF; | ||
1604 | else | 2632 | else |
1605 | lp->linkspeed = 10; | 2633 | advertize &= ~ADVERTISE_10HALF; |
1606 | if (neg_result & (MII_AN_TX_FDX | MII_AN_10_FDX)) | 2634 | if (bmsr & BMSR_10FULL) |
1607 | lp->fullduplex = 1; | 2635 | advertize |= ADVERTISE_10FULL; |
1608 | else | 2636 | else |
1609 | lp->fullduplex = 0; | 2637 | advertize &= ~ADVERTISE_10FULL; |
1610 | done: | 2638 | if (bmsr & BMSR_100HALF) |
1611 | ; | 2639 | advertize |= ADVERTISE_100HALF; |
2640 | else | ||
2641 | advertize &= ~ADVERTISE_100HALF; | ||
2642 | if (bmsr & BMSR_100FULL) | ||
2643 | advertize |= ADVERTISE_100FULL; | ||
2644 | else | ||
2645 | advertize &= ~ADVERTISE_100FULL; | ||
2646 | } | ||
2647 | |||
2648 | tc_mdio_write(dev, pid, MII_ADVERTISE, advertize); | ||
2649 | |||
2650 | /* Enable Auto-Negotiation, this is usually on already... */ | ||
2651 | bmcr |= BMCR_ANENABLE; | ||
2652 | tc_mdio_write(dev, pid, MII_BMCR, bmcr); | ||
2653 | |||
2654 | /* Restart it to make sure it is going. */ | ||
2655 | bmcr |= BMCR_ANRESTART; | ||
2656 | tc_mdio_write(dev, pid, MII_BMCR, bmcr); | ||
2657 | printk(KERN_DEBUG "%s: ADVERTISE %x BMCR %x\n", dev->name, advertize, bmcr); | ||
2658 | |||
2659 | /* BMCR_ANRESTART self clears when the process has begun. */ | ||
2660 | timeout = 64; /* More than enough. */ | ||
2661 | while (--timeout) { | ||
2662 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); | ||
2663 | if (!(bmcr & BMCR_ANRESTART)) | ||
2664 | break; /* got it. */ | ||
2665 | udelay(10); | ||
1612 | } | 2666 | } |
2667 | if (!timeout) { | ||
2668 | printk(KERN_ERR "%s: TC35815 would not start auto " | ||
2669 | "negotiation BMCR=0x%04x\n", | ||
2670 | dev->name, bmcr); | ||
2671 | printk(KERN_NOTICE "%s: Performing force link " | ||
2672 | "detection.\n", dev->name); | ||
2673 | goto force_link; | ||
2674 | } else { | ||
2675 | printk(KERN_DEBUG "%s: auto negotiation started.\n", dev->name); | ||
2676 | lp->timer_state = arbwait; | ||
2677 | } | ||
2678 | } else { | ||
2679 | force_link: | ||
2680 | /* Force the link up, trying first a particular mode. | ||
2681 | * Either we are here at the request of ethtool or | ||
2682 | * because the Happy Meal would not start to autoneg. | ||
2683 | */ | ||
2684 | |||
2685 | /* Disable auto-negotiation in BMCR, enable the duplex and | ||
2686 | * speed setting, init the timer state machine, and fire it off. | ||
2687 | */ | ||
2688 | if (ep == NULL || ep->autoneg == AUTONEG_ENABLE) { | ||
2689 | bmcr = BMCR_SPEED100; | ||
2690 | } else { | ||
2691 | if (ep->speed == SPEED_100) | ||
2692 | bmcr = BMCR_SPEED100; | ||
2693 | else | ||
2694 | bmcr = 0; | ||
2695 | if (ep->duplex == DUPLEX_FULL) | ||
2696 | bmcr |= BMCR_FULLDPLX; | ||
2697 | } | ||
2698 | tc_mdio_write(dev, pid, MII_BMCR, bmcr); | ||
2699 | |||
2700 | /* OK, seems we need do disable the transceiver for the first | ||
2701 | * tick to make sure we get an accurate link state at the | ||
2702 | * second tick. | ||
2703 | */ | ||
2704 | lp->timer_state = ltrywait; | ||
1613 | } | 2705 | } |
1614 | 2706 | ||
1615 | ctl = 0; | 2707 | del_timer(&lp->timer); |
1616 | if (lp->linkspeed == 100) | 2708 | lp->timer_ticks = 0; |
1617 | ctl |= MIICNTL_SPEED; | 2709 | lp->timer.expires = jiffies + msecs_to_jiffies(1200); |
1618 | if (lp->fullduplex) | 2710 | add_timer(&lp->timer); |
1619 | ctl |= MIICNTL_FDX; | 2711 | } |
1620 | tc_phy_write(dev, ctl, tr, 0, MII_CONTROL); | ||
1621 | 2712 | ||
1622 | if (lp->fullduplex) { | 2713 | static void tc35815_find_phy(struct net_device *dev) |
1623 | tc_writel(tc_readl(&tr->MAC_Ctl) | MAC_FullDup, &tr->MAC_Ctl); | 2714 | { |
2715 | struct tc35815_local *lp = dev->priv; | ||
2716 | int pid = lp->phy_addr; | ||
2717 | unsigned short id0; | ||
2718 | |||
2719 | /* find MII phy */ | ||
2720 | for (pid = 31; pid >= 0; pid--) { | ||
2721 | id0 = tc_mdio_read(dev, pid, MII_BMSR); | ||
2722 | if (id0 != 0xffff && id0 != 0x0000 && | ||
2723 | (id0 & BMSR_RESV) != (0xffff & BMSR_RESV) /* paranoia? */ | ||
2724 | ) { | ||
2725 | lp->phy_addr = pid; | ||
2726 | break; | ||
2727 | } | ||
1624 | } | 2728 | } |
2729 | if (pid < 0) { | ||
2730 | printk(KERN_ERR "%s: No MII Phy found.\n", | ||
2731 | dev->name); | ||
2732 | lp->phy_addr = pid = 0; | ||
2733 | } | ||
2734 | |||
2735 | lp->mii_id[0] = tc_mdio_read(dev, pid, MII_PHYSID1); | ||
2736 | lp->mii_id[1] = tc_mdio_read(dev, pid, MII_PHYSID2); | ||
2737 | if (netif_msg_hw(lp)) | ||
2738 | printk(KERN_INFO "%s: PHY(%02x) ID %04x %04x\n", dev->name, | ||
2739 | pid, lp->mii_id[0], lp->mii_id[1]); | ||
1625 | } | 2740 | } |
1626 | 2741 | ||
1627 | static void tc35815_chip_reset(struct net_device *dev) | 2742 | static void tc35815_phy_chip_init(struct net_device *dev) |
1628 | { | 2743 | { |
1629 | struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; | 2744 | struct tc35815_local *lp = dev->priv; |
2745 | int pid = lp->phy_addr; | ||
2746 | unsigned short bmcr; | ||
2747 | struct ethtool_cmd ecmd, *ep; | ||
2748 | |||
2749 | /* dis-isolate if needed. */ | ||
2750 | bmcr = tc_mdio_read(dev, pid, MII_BMCR); | ||
2751 | if (bmcr & BMCR_ISOLATE) { | ||
2752 | int count = 32; | ||
2753 | printk(KERN_DEBUG "%s: unisolating...", dev->name); | ||
2754 | tc_mdio_write(dev, pid, MII_BMCR, bmcr & ~BMCR_ISOLATE); | ||
2755 | while (--count) { | ||
2756 | if (!(tc_mdio_read(dev, pid, MII_BMCR) & BMCR_ISOLATE)) | ||
2757 | break; | ||
2758 | udelay(20); | ||
2759 | } | ||
2760 | printk(" %s.\n", count ? "done" : "failed"); | ||
2761 | } | ||
2762 | |||
2763 | if (options.speed && options.duplex) { | ||
2764 | ecmd.autoneg = AUTONEG_DISABLE; | ||
2765 | ecmd.speed = options.speed == 10 ? SPEED_10 : SPEED_100; | ||
2766 | ecmd.duplex = options.duplex == 1 ? DUPLEX_HALF : DUPLEX_FULL; | ||
2767 | ep = &ecmd; | ||
2768 | } else { | ||
2769 | ep = NULL; | ||
2770 | } | ||
2771 | tc35815_start_auto_negotiation(dev, ep); | ||
2772 | } | ||
1630 | 2773 | ||
2774 | static void tc35815_chip_reset(struct net_device *dev) | ||
2775 | { | ||
2776 | struct tc35815_regs __iomem *tr = | ||
2777 | (struct tc35815_regs __iomem *)dev->base_addr; | ||
2778 | int i; | ||
1631 | /* reset the controller */ | 2779 | /* reset the controller */ |
1632 | tc_writel(MAC_Reset, &tr->MAC_Ctl); | 2780 | tc_writel(MAC_Reset, &tr->MAC_Ctl); |
1633 | while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) | 2781 | udelay(4); /* 3200ns */ |
1634 | ; | 2782 | i = 0; |
1635 | 2783 | while (tc_readl(&tr->MAC_Ctl) & MAC_Reset) { | |
2784 | if (i++ > 100) { | ||
2785 | printk(KERN_ERR "%s: MAC reset failed.\n", dev->name); | ||
2786 | break; | ||
2787 | } | ||
2788 | mdelay(1); | ||
2789 | } | ||
1636 | tc_writel(0, &tr->MAC_Ctl); | 2790 | tc_writel(0, &tr->MAC_Ctl); |
1637 | 2791 | ||
1638 | /* initialize registers to default value */ | 2792 | /* initialize registers to default value */ |
@@ -1650,90 +2804,142 @@ static void tc35815_chip_reset(struct net_device *dev) | |||
1650 | tc_writel(0, &tr->CAM_Ena); | 2804 | tc_writel(0, &tr->CAM_Ena); |
1651 | (void)tc_readl(&tr->Miss_Cnt); /* Read to clear */ | 2805 | (void)tc_readl(&tr->Miss_Cnt); /* Read to clear */ |
1652 | 2806 | ||
2807 | /* initialize internal SRAM */ | ||
2808 | tc_writel(DMA_TestMode, &tr->DMA_Ctl); | ||
2809 | for (i = 0; i < 0x1000; i += 4) { | ||
2810 | tc_writel(i, &tr->CAM_Adr); | ||
2811 | tc_writel(0, &tr->CAM_Data); | ||
2812 | } | ||
2813 | tc_writel(0, &tr->DMA_Ctl); | ||
1653 | } | 2814 | } |
1654 | 2815 | ||
1655 | static void tc35815_chip_init(struct net_device *dev) | 2816 | static void tc35815_chip_init(struct net_device *dev) |
1656 | { | 2817 | { |
1657 | struct tc35815_local *lp = dev->priv; | 2818 | struct tc35815_local *lp = dev->priv; |
1658 | struct tc35815_regs *tr = (struct tc35815_regs*)dev->base_addr; | 2819 | struct tc35815_regs __iomem *tr = |
1659 | unsigned long flags; | 2820 | (struct tc35815_regs __iomem *)dev->base_addr; |
1660 | unsigned long txctl = TX_CTL_CMD; | 2821 | unsigned long txctl = TX_CTL_CMD; |
1661 | 2822 | ||
1662 | tc35815_phy_chip_init(dev); | 2823 | tc35815_phy_chip_init(dev); |
1663 | 2824 | ||
1664 | /* load station address to CAM */ | 2825 | /* load station address to CAM */ |
1665 | tc35815_set_cam_entry(tr, CAM_ENTRY_SOURCE, dev->dev_addr); | 2826 | tc35815_set_cam_entry(dev, CAM_ENTRY_SOURCE, dev->dev_addr); |
1666 | 2827 | ||
1667 | /* Enable CAM (broadcast and unicast) */ | 2828 | /* Enable CAM (broadcast and unicast) */ |
1668 | tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); | 2829 | tc_writel(CAM_Ena_Bit(CAM_ENTRY_SOURCE), &tr->CAM_Ena); |
1669 | tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); | 2830 | tc_writel(CAM_CompEn | CAM_BroadAcc, &tr->CAM_Ctl); |
1670 | 2831 | ||
1671 | spin_lock_irqsave(&lp->lock, flags); | 2832 | /* Use DMA_RxAlign_2 to make IP header 4-byte aligned. */ |
1672 | 2833 | if (HAVE_DMA_RXALIGN(lp)) | |
1673 | tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); | 2834 | tc_writel(DMA_BURST_SIZE | DMA_RxAlign_2, &tr->DMA_Ctl); |
1674 | 2835 | else | |
2836 | tc_writel(DMA_BURST_SIZE, &tr->DMA_Ctl); | ||
2837 | #ifdef TC35815_USE_PACKEDBUFFER | ||
1675 | tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ | 2838 | tc_writel(RxFrag_EnPack | ETH_ZLEN, &tr->RxFragSize); /* Packing */ |
2839 | #else | ||
2840 | tc_writel(ETH_ZLEN, &tr->RxFragSize); | ||
2841 | #endif | ||
1676 | tc_writel(0, &tr->TxPollCtr); /* Batch mode */ | 2842 | tc_writel(0, &tr->TxPollCtr); /* Batch mode */ |
1677 | tc_writel(TX_THRESHOLD, &tr->TxThrsh); | 2843 | tc_writel(TX_THRESHOLD, &tr->TxThrsh); |
1678 | tc_writel(INT_EN_CMD, &tr->Int_En); | 2844 | tc_writel(INT_EN_CMD, &tr->Int_En); |
1679 | 2845 | ||
1680 | /* set queues */ | 2846 | /* set queues */ |
1681 | tc_writel(virt_to_bus(lp->rfd_base), &tr->FDA_Bas); | 2847 | tc_writel(fd_virt_to_bus(lp, lp->rfd_base), &tr->FDA_Bas); |
1682 | tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base, | 2848 | tc_writel((unsigned long)lp->rfd_limit - (unsigned long)lp->rfd_base, |
1683 | &tr->FDA_Lim); | 2849 | &tr->FDA_Lim); |
1684 | /* | 2850 | /* |
1685 | * Activation method: | 2851 | * Activation method: |
1686 | * First, enable eht MAC Transmitter and the DMA Receive circuits. | 2852 | * First, enable the MAC Transmitter and the DMA Receive circuits. |
1687 | * Then enable the DMA Transmitter and the MAC Receive circuits. | 2853 | * Then enable the DMA Transmitter and the MAC Receive circuits. |
1688 | */ | 2854 | */ |
1689 | tc_writel(virt_to_bus(lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */ | 2855 | tc_writel(fd_virt_to_bus(lp, lp->fbl_ptr), &tr->BLFrmPtr); /* start DMA receiver */ |
1690 | tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */ | 2856 | tc_writel(RX_CTL_CMD, &tr->Rx_Ctl); /* start MAC receiver */ |
2857 | |||
1691 | /* start MAC transmitter */ | 2858 | /* start MAC transmitter */ |
2859 | #ifndef NO_CHECK_CARRIER | ||
2860 | /* TX4939 does not have EnLCarr */ | ||
2861 | if (lp->boardtype == TC35815_TX4939) | ||
2862 | txctl &= ~Tx_EnLCarr; | ||
2863 | #ifdef WORKAROUND_LOSTCAR | ||
1692 | /* WORKAROUND: ignore LostCrS in full duplex operation */ | 2864 | /* WORKAROUND: ignore LostCrS in full duplex operation */ |
1693 | if (lp->fullduplex) | 2865 | if ((lp->timer_state != asleep && lp->timer_state != lcheck) || |
1694 | txctl = TX_CTL_CMD & ~Tx_EnLCarr; | 2866 | lp->fullduplex) |
2867 | txctl &= ~Tx_EnLCarr; | ||
2868 | #endif | ||
2869 | #endif /* !NO_CHECK_CARRIER */ | ||
1695 | #ifdef GATHER_TXINT | 2870 | #ifdef GATHER_TXINT |
1696 | txctl &= ~Tx_EnComp; /* disable global tx completion int. */ | 2871 | txctl &= ~Tx_EnComp; /* disable global tx completion int. */ |
1697 | #endif | 2872 | #endif |
1698 | tc_writel(txctl, &tr->Tx_Ctl); | 2873 | tc_writel(txctl, &tr->Tx_Ctl); |
1699 | #if 0 /* No need to polling */ | 2874 | } |
1700 | tc_writel(virt_to_bus(lp->tfd_base), &tr->TxFrmPtr); /* start DMA transmitter */ | 2875 | |
1701 | #endif | 2876 | #ifdef CONFIG_PM |
2877 | static int tc35815_suspend(struct pci_dev *pdev, pm_message_t state) | ||
2878 | { | ||
2879 | struct net_device *dev = pci_get_drvdata(pdev); | ||
2880 | struct tc35815_local *lp = dev->priv; | ||
2881 | unsigned long flags; | ||
2882 | |||
2883 | pci_save_state(pdev); | ||
2884 | if (!netif_running(dev)) | ||
2885 | return 0; | ||
2886 | netif_device_detach(dev); | ||
2887 | spin_lock_irqsave(&lp->lock, flags); | ||
2888 | del_timer(&lp->timer); /* Kill if running */ | ||
2889 | tc35815_chip_reset(dev); | ||
1702 | spin_unlock_irqrestore(&lp->lock, flags); | 2890 | spin_unlock_irqrestore(&lp->lock, flags); |
2891 | pci_set_power_state(pdev, PCI_D3hot); | ||
2892 | return 0; | ||
1703 | } | 2893 | } |
1704 | 2894 | ||
1705 | static struct pci_driver tc35815_driver = { | 2895 | static int tc35815_resume(struct pci_dev *pdev) |
1706 | .name = TC35815_MODULE_NAME, | 2896 | { |
1707 | .probe = tc35815_probe, | 2897 | struct net_device *dev = pci_get_drvdata(pdev); |
1708 | .remove = NULL, | 2898 | struct tc35815_local *lp = dev->priv; |
1709 | .id_table = tc35815_pci_tbl, | 2899 | unsigned long flags; |
2900 | |||
2901 | pci_restore_state(pdev); | ||
2902 | if (!netif_running(dev)) | ||
2903 | return 0; | ||
2904 | pci_set_power_state(pdev, PCI_D0); | ||
2905 | spin_lock_irqsave(&lp->lock, flags); | ||
2906 | tc35815_restart(dev); | ||
2907 | spin_unlock_irqrestore(&lp->lock, flags); | ||
2908 | netif_device_attach(dev); | ||
2909 | return 0; | ||
2910 | } | ||
2911 | #endif /* CONFIG_PM */ | ||
2912 | |||
2913 | static struct pci_driver tc35815_pci_driver = { | ||
2914 | .name = MODNAME, | ||
2915 | .id_table = tc35815_pci_tbl, | ||
2916 | .probe = tc35815_init_one, | ||
2917 | .remove = __devexit_p(tc35815_remove_one), | ||
2918 | #ifdef CONFIG_PM | ||
2919 | .suspend = tc35815_suspend, | ||
2920 | .resume = tc35815_resume, | ||
2921 | #endif | ||
1710 | }; | 2922 | }; |
1711 | 2923 | ||
2924 | module_param_named(speed, options.speed, int, 0); | ||
2925 | MODULE_PARM_DESC(speed, "0:auto, 10:10Mbps, 100:100Mbps"); | ||
2926 | module_param_named(duplex, options.duplex, int, 0); | ||
2927 | MODULE_PARM_DESC(duplex, "0:auto, 1:half, 2:full"); | ||
2928 | module_param_named(doforce, options.doforce, int, 0); | ||
2929 | MODULE_PARM_DESC(doforce, "try force link mode if auto-negotiation failed"); | ||
2930 | |||
1712 | static int __init tc35815_init_module(void) | 2931 | static int __init tc35815_init_module(void) |
1713 | { | 2932 | { |
1714 | return pci_register_driver(&tc35815_driver); | 2933 | return pci_register_driver(&tc35815_pci_driver); |
1715 | } | 2934 | } |
1716 | 2935 | ||
1717 | static void __exit tc35815_cleanup_module(void) | 2936 | static void __exit tc35815_cleanup_module(void) |
1718 | { | 2937 | { |
1719 | struct net_device *next_dev; | 2938 | pci_unregister_driver(&tc35815_pci_driver); |
1720 | |||
1721 | /* | ||
1722 | * TODO: implement a tc35815_driver.remove hook, and | ||
1723 | * move this code into that function. Then, delete | ||
1724 | * all root_tc35815_dev list handling code. | ||
1725 | */ | ||
1726 | while (root_tc35815_dev) { | ||
1727 | struct net_device *dev = root_tc35815_dev; | ||
1728 | next_dev = ((struct tc35815_local *)dev->priv)->next_module; | ||
1729 | iounmap((void *)(dev->base_addr)); | ||
1730 | unregister_netdev(dev); | ||
1731 | free_netdev(dev); | ||
1732 | root_tc35815_dev = next_dev; | ||
1733 | } | ||
1734 | |||
1735 | pci_unregister_driver(&tc35815_driver); | ||
1736 | } | 2939 | } |
1737 | 2940 | ||
1738 | module_init(tc35815_init_module); | 2941 | module_init(tc35815_init_module); |
1739 | module_exit(tc35815_cleanup_module); | 2942 | module_exit(tc35815_cleanup_module); |
2943 | |||
2944 | MODULE_DESCRIPTION("TOSHIBA TC35815 PCI 10M/100M Ethernet driver"); | ||
2945 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index b3a64ca98634..4ed67ff0e81e 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c | |||
@@ -55,9 +55,6 @@ | |||
55 | 55 | ||
56 | TODO | 56 | TODO |
57 | 57 | ||
58 | Implement pci_driver::suspend() and pci_driver::resume() | ||
59 | power management methods. | ||
60 | |||
61 | Check on 64 bit boxes. | 58 | Check on 64 bit boxes. |
62 | Check and fix on big endian boxes. | 59 | Check and fix on big endian boxes. |
63 | 60 | ||
@@ -125,6 +122,11 @@ | |||
125 | #define DM9801_NOISE_FLOOR 8 | 122 | #define DM9801_NOISE_FLOOR 8 |
126 | #define DM9802_NOISE_FLOOR 5 | 123 | #define DM9802_NOISE_FLOOR 5 |
127 | 124 | ||
125 | #define DMFE_WOL_LINKCHANGE 0x20000000 | ||
126 | #define DMFE_WOL_SAMPLEPACKET 0x10000000 | ||
127 | #define DMFE_WOL_MAGICPACKET 0x08000000 | ||
128 | |||
129 | |||
128 | #define DMFE_10MHF 0 | 130 | #define DMFE_10MHF 0 |
129 | #define DMFE_100MHF 1 | 131 | #define DMFE_100MHF 1 |
130 | #define DMFE_10MFD 4 | 132 | #define DMFE_10MFD 4 |
@@ -251,6 +253,7 @@ struct dmfe_board_info { | |||
251 | u8 wait_reset; /* Hardware failed, need to reset */ | 253 | u8 wait_reset; /* Hardware failed, need to reset */ |
252 | u8 dm910x_chk_mode; /* Operating mode check */ | 254 | u8 dm910x_chk_mode; /* Operating mode check */ |
253 | u8 first_in_callback; /* Flag to record state */ | 255 | u8 first_in_callback; /* Flag to record state */ |
256 | u8 wol_mode; /* user WOL settings */ | ||
254 | struct timer_list timer; | 257 | struct timer_list timer; |
255 | 258 | ||
256 | /* System defined statistic counter */ | 259 | /* System defined statistic counter */ |
@@ -431,6 +434,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, | |||
431 | db->chip_id = ent->driver_data; | 434 | db->chip_id = ent->driver_data; |
432 | db->ioaddr = pci_resource_start(pdev, 0); | 435 | db->ioaddr = pci_resource_start(pdev, 0); |
433 | db->chip_revision = dev_rev; | 436 | db->chip_revision = dev_rev; |
437 | db->wol_mode = 0; | ||
434 | 438 | ||
435 | db->pdev = pdev; | 439 | db->pdev = pdev; |
436 | 440 | ||
@@ -1065,7 +1069,11 @@ static void dmfe_set_filter_mode(struct DEVICE * dev) | |||
1065 | spin_unlock_irqrestore(&db->lock, flags); | 1069 | spin_unlock_irqrestore(&db->lock, flags); |
1066 | } | 1070 | } |
1067 | 1071 | ||
1068 | static void netdev_get_drvinfo(struct net_device *dev, | 1072 | /* |
1073 | * Ethtool interace | ||
1074 | */ | ||
1075 | |||
1076 | static void dmfe_ethtool_get_drvinfo(struct net_device *dev, | ||
1069 | struct ethtool_drvinfo *info) | 1077 | struct ethtool_drvinfo *info) |
1070 | { | 1078 | { |
1071 | struct dmfe_board_info *np = netdev_priv(dev); | 1079 | struct dmfe_board_info *np = netdev_priv(dev); |
@@ -1079,9 +1087,35 @@ static void netdev_get_drvinfo(struct net_device *dev, | |||
1079 | dev->base_addr, dev->irq); | 1087 | dev->base_addr, dev->irq); |
1080 | } | 1088 | } |
1081 | 1089 | ||
1090 | static int dmfe_ethtool_set_wol(struct net_device *dev, | ||
1091 | struct ethtool_wolinfo *wolinfo) | ||
1092 | { | ||
1093 | struct dmfe_board_info *db = netdev_priv(dev); | ||
1094 | |||
1095 | if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST | | ||
1096 | WAKE_ARP | WAKE_MAGICSECURE)) | ||
1097 | return -EOPNOTSUPP; | ||
1098 | |||
1099 | db->wol_mode = wolinfo->wolopts; | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | static void dmfe_ethtool_get_wol(struct net_device *dev, | ||
1104 | struct ethtool_wolinfo *wolinfo) | ||
1105 | { | ||
1106 | struct dmfe_board_info *db = netdev_priv(dev); | ||
1107 | |||
1108 | wolinfo->supported = WAKE_PHY | WAKE_MAGIC; | ||
1109 | wolinfo->wolopts = db->wol_mode; | ||
1110 | return; | ||
1111 | } | ||
1112 | |||
1113 | |||
1082 | static const struct ethtool_ops netdev_ethtool_ops = { | 1114 | static const struct ethtool_ops netdev_ethtool_ops = { |
1083 | .get_drvinfo = netdev_get_drvinfo, | 1115 | .get_drvinfo = dmfe_ethtool_get_drvinfo, |
1084 | .get_link = ethtool_op_get_link, | 1116 | .get_link = ethtool_op_get_link, |
1117 | .set_wol = dmfe_ethtool_set_wol, | ||
1118 | .get_wol = dmfe_ethtool_get_wol, | ||
1085 | }; | 1119 | }; |
1086 | 1120 | ||
1087 | /* | 1121 | /* |
@@ -2050,11 +2084,85 @@ static struct pci_device_id dmfe_pci_tbl[] = { | |||
2050 | MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl); | 2084 | MODULE_DEVICE_TABLE(pci, dmfe_pci_tbl); |
2051 | 2085 | ||
2052 | 2086 | ||
2087 | #ifdef CONFIG_PM | ||
2088 | static int dmfe_suspend(struct pci_dev *pci_dev, pm_message_t state) | ||
2089 | { | ||
2090 | struct net_device *dev = pci_get_drvdata(pci_dev); | ||
2091 | struct dmfe_board_info *db = netdev_priv(dev); | ||
2092 | u32 tmp; | ||
2093 | |||
2094 | /* Disable upper layer interface */ | ||
2095 | netif_device_detach(dev); | ||
2096 | |||
2097 | /* Disable Tx/Rx */ | ||
2098 | db->cr6_data &= ~(CR6_RXSC | CR6_TXSC); | ||
2099 | update_cr6(db->cr6_data, dev->base_addr); | ||
2100 | |||
2101 | /* Disable Interrupt */ | ||
2102 | outl(0, dev->base_addr + DCR7); | ||
2103 | outl(inl (dev->base_addr + DCR5), dev->base_addr + DCR5); | ||
2104 | |||
2105 | /* Fre RX buffers */ | ||
2106 | dmfe_free_rxbuffer(db); | ||
2107 | |||
2108 | /* Enable WOL */ | ||
2109 | pci_read_config_dword(pci_dev, 0x40, &tmp); | ||
2110 | tmp &= ~(DMFE_WOL_LINKCHANGE|DMFE_WOL_MAGICPACKET); | ||
2111 | |||
2112 | if (db->wol_mode & WAKE_PHY) | ||
2113 | tmp |= DMFE_WOL_LINKCHANGE; | ||
2114 | if (db->wol_mode & WAKE_MAGIC) | ||
2115 | tmp |= DMFE_WOL_MAGICPACKET; | ||
2116 | |||
2117 | pci_write_config_dword(pci_dev, 0x40, tmp); | ||
2118 | |||
2119 | pci_enable_wake(pci_dev, PCI_D3hot, 1); | ||
2120 | pci_enable_wake(pci_dev, PCI_D3cold, 1); | ||
2121 | |||
2122 | /* Power down device*/ | ||
2123 | pci_set_power_state(pci_dev, pci_choose_state (pci_dev,state)); | ||
2124 | pci_save_state(pci_dev); | ||
2125 | |||
2126 | return 0; | ||
2127 | } | ||
2128 | |||
2129 | static int dmfe_resume(struct pci_dev *pci_dev) | ||
2130 | { | ||
2131 | struct net_device *dev = pci_get_drvdata(pci_dev); | ||
2132 | u32 tmp; | ||
2133 | |||
2134 | pci_restore_state(pci_dev); | ||
2135 | pci_set_power_state(pci_dev, PCI_D0); | ||
2136 | |||
2137 | /* Re-initilize DM910X board */ | ||
2138 | dmfe_init_dm910x(dev); | ||
2139 | |||
2140 | /* Disable WOL */ | ||
2141 | pci_read_config_dword(pci_dev, 0x40, &tmp); | ||
2142 | |||
2143 | tmp &= ~(DMFE_WOL_LINKCHANGE | DMFE_WOL_MAGICPACKET); | ||
2144 | pci_write_config_dword(pci_dev, 0x40, tmp); | ||
2145 | |||
2146 | pci_enable_wake(pci_dev, PCI_D3hot, 0); | ||
2147 | pci_enable_wake(pci_dev, PCI_D3cold, 0); | ||
2148 | |||
2149 | /* Restart upper layer interface */ | ||
2150 | netif_device_attach(dev); | ||
2151 | |||
2152 | return 0; | ||
2153 | } | ||
2154 | #else | ||
2155 | #define dmfe_suspend NULL | ||
2156 | #define dmfe_resume NULL | ||
2157 | #endif | ||
2158 | |||
2053 | static struct pci_driver dmfe_driver = { | 2159 | static struct pci_driver dmfe_driver = { |
2054 | .name = "dmfe", | 2160 | .name = "dmfe", |
2055 | .id_table = dmfe_pci_tbl, | 2161 | .id_table = dmfe_pci_tbl, |
2056 | .probe = dmfe_init_one, | 2162 | .probe = dmfe_init_one, |
2057 | .remove = __devexit_p(dmfe_remove_one), | 2163 | .remove = __devexit_p(dmfe_remove_one), |
2164 | .suspend = dmfe_suspend, | ||
2165 | .resume = dmfe_resume | ||
2058 | }; | 2166 | }; |
2059 | 2167 | ||
2060 | MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw"); | 2168 | MODULE_AUTHOR("Sten Wang, sten_wang@davicom.com.tw"); |
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index e86df07769a1..9b08afbd1f65 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c | |||
@@ -673,7 +673,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) | |||
673 | if (tp->link_change) | 673 | if (tp->link_change) |
674 | (tp->link_change)(dev, csr5); | 674 | (tp->link_change)(dev, csr5); |
675 | } | 675 | } |
676 | if (csr5 & SytemError) { | 676 | if (csr5 & SystemError) { |
677 | int error = (csr5 >> 23) & 7; | 677 | int error = (csr5 >> 23) & 7; |
678 | /* oops, we hit a PCI error. The code produced corresponds | 678 | /* oops, we hit a PCI error. The code produced corresponds |
679 | * to the reason: | 679 | * to the reason: |
@@ -743,7 +743,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) | |||
743 | TxFIFOUnderflow | | 743 | TxFIFOUnderflow | |
744 | TxJabber | | 744 | TxJabber | |
745 | TPLnkFail | | 745 | TPLnkFail | |
746 | SytemError )) != 0); | 746 | SystemError )) != 0); |
747 | #else | 747 | #else |
748 | } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); | 748 | } while ((csr5 & (NormalIntr|AbnormalIntr)) != 0); |
749 | 749 | ||
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c index 20bd52b86993..b56256636543 100644 --- a/drivers/net/tulip/media.c +++ b/drivers/net/tulip/media.c | |||
@@ -44,8 +44,10 @@ static const unsigned char comet_miireg2offset[32] = { | |||
44 | 44 | ||
45 | /* MII transceiver control section. | 45 | /* MII transceiver control section. |
46 | Read and write the MII registers using software-generated serial | 46 | Read and write the MII registers using software-generated serial |
47 | MDIO protocol. See the MII specifications or DP83840A data sheet | 47 | MDIO protocol. |
48 | for details. */ | 48 | See IEEE 802.3-2002.pdf (Section 2, Chapter "22.2.4 Management functions") |
49 | or DP83840A data sheet for more details. | ||
50 | */ | ||
49 | 51 | ||
50 | int tulip_mdio_read(struct net_device *dev, int phy_id, int location) | 52 | int tulip_mdio_read(struct net_device *dev, int phy_id, int location) |
51 | { | 53 | { |
@@ -261,24 +263,56 @@ void tulip_select_media(struct net_device *dev, int startup) | |||
261 | u16 *reset_sequence = &((u16*)(p+3))[init_length]; | 263 | u16 *reset_sequence = &((u16*)(p+3))[init_length]; |
262 | int reset_length = p[2 + init_length*2]; | 264 | int reset_length = p[2 + init_length*2]; |
263 | misc_info = reset_sequence + reset_length; | 265 | misc_info = reset_sequence + reset_length; |
264 | if (startup) | 266 | if (startup) { |
267 | int timeout = 10; /* max 1 ms */ | ||
265 | for (i = 0; i < reset_length; i++) | 268 | for (i = 0; i < reset_length; i++) |
266 | iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); | 269 | iowrite32(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15); |
270 | |||
271 | /* flush posted writes */ | ||
272 | ioread32(ioaddr + CSR15); | ||
273 | |||
274 | /* Sect 3.10.3 in DP83840A.pdf (p39) */ | ||
275 | udelay(500); | ||
276 | |||
277 | /* Section 4.2 in DP83840A.pdf (p43) */ | ||
278 | /* and IEEE 802.3 "22.2.4.1.1 Reset" */ | ||
279 | while (timeout-- && | ||
280 | (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) | ||
281 | udelay(100); | ||
282 | } | ||
267 | for (i = 0; i < init_length; i++) | 283 | for (i = 0; i < init_length; i++) |
268 | iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); | 284 | iowrite32(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15); |
285 | |||
286 | ioread32(ioaddr + CSR15); /* flush posted writes */ | ||
269 | } else { | 287 | } else { |
270 | u8 *init_sequence = p + 2; | 288 | u8 *init_sequence = p + 2; |
271 | u8 *reset_sequence = p + 3 + init_length; | 289 | u8 *reset_sequence = p + 3 + init_length; |
272 | int reset_length = p[2 + init_length]; | 290 | int reset_length = p[2 + init_length]; |
273 | misc_info = (u16*)(reset_sequence + reset_length); | 291 | misc_info = (u16*)(reset_sequence + reset_length); |
274 | if (startup) { | 292 | if (startup) { |
293 | int timeout = 10; /* max 1 ms */ | ||
275 | iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); | 294 | iowrite32(mtable->csr12dir | 0x100, ioaddr + CSR12); |
276 | for (i = 0; i < reset_length; i++) | 295 | for (i = 0; i < reset_length; i++) |
277 | iowrite32(reset_sequence[i], ioaddr + CSR12); | 296 | iowrite32(reset_sequence[i], ioaddr + CSR12); |
297 | |||
298 | /* flush posted writes */ | ||
299 | ioread32(ioaddr + CSR12); | ||
300 | |||
301 | /* Sect 3.10.3 in DP83840A.pdf (p39) */ | ||
302 | udelay(500); | ||
303 | |||
304 | /* Section 4.2 in DP83840A.pdf (p43) */ | ||
305 | /* and IEEE 802.3 "22.2.4.1.1 Reset" */ | ||
306 | while (timeout-- && | ||
307 | (tulip_mdio_read (dev, phy_num, MII_BMCR) & BMCR_RESET)) | ||
308 | udelay(100); | ||
278 | } | 309 | } |
279 | for (i = 0; i < init_length; i++) | 310 | for (i = 0; i < init_length; i++) |
280 | iowrite32(init_sequence[i], ioaddr + CSR12); | 311 | iowrite32(init_sequence[i], ioaddr + CSR12); |
312 | |||
313 | ioread32(ioaddr + CSR12); /* flush posted writes */ | ||
281 | } | 314 | } |
315 | |||
282 | tmp_info = get_u16(&misc_info[1]); | 316 | tmp_info = get_u16(&misc_info[1]); |
283 | if (tmp_info) | 317 | if (tmp_info) |
284 | tp->advertising[phy_num] = tmp_info | 1; | 318 | tp->advertising[phy_num] = tmp_info | 1; |
diff --git a/drivers/net/tulip/tulip.h b/drivers/net/tulip/tulip.h index 25f25da76917..c840d2e67b23 100644 --- a/drivers/net/tulip/tulip.h +++ b/drivers/net/tulip/tulip.h | |||
@@ -132,7 +132,7 @@ enum pci_cfg_driver_reg { | |||
132 | /* The bits in the CSR5 status registers, mostly interrupt sources. */ | 132 | /* The bits in the CSR5 status registers, mostly interrupt sources. */ |
133 | enum status_bits { | 133 | enum status_bits { |
134 | TimerInt = 0x800, | 134 | TimerInt = 0x800, |
135 | SytemError = 0x2000, | 135 | SystemError = 0x2000, |
136 | TPLnkFail = 0x1000, | 136 | TPLnkFail = 0x1000, |
137 | TPLnkPass = 0x10, | 137 | TPLnkPass = 0x10, |
138 | NormalIntr = 0x10000, | 138 | NormalIntr = 0x10000, |
@@ -482,8 +482,11 @@ static inline void tulip_stop_rxtx(struct tulip_private *tp) | |||
482 | udelay(10); | 482 | udelay(10); |
483 | 483 | ||
484 | if (!i) | 484 | if (!i) |
485 | printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed\n", | 485 | printk(KERN_DEBUG "%s: tulip_stop_rxtx() failed" |
486 | pci_name(tp->pdev)); | 486 | " (CSR5 0x%x CSR6 0x%x)\n", |
487 | pci_name(tp->pdev), | ||
488 | ioread32(ioaddr + CSR5), | ||
489 | ioread32(ioaddr + CSR6)); | ||
487 | } | 490 | } |
488 | } | 491 | } |
489 | 492 | ||
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index e9bf526ec534..041af63f2811 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c | |||
@@ -17,11 +17,11 @@ | |||
17 | 17 | ||
18 | #define DRV_NAME "tulip" | 18 | #define DRV_NAME "tulip" |
19 | #ifdef CONFIG_TULIP_NAPI | 19 | #ifdef CONFIG_TULIP_NAPI |
20 | #define DRV_VERSION "1.1.14-NAPI" /* Keep at least for test */ | 20 | #define DRV_VERSION "1.1.15-NAPI" /* Keep at least for test */ |
21 | #else | 21 | #else |
22 | #define DRV_VERSION "1.1.14" | 22 | #define DRV_VERSION "1.1.15" |
23 | #endif | 23 | #endif |
24 | #define DRV_RELDATE "May 11, 2002" | 24 | #define DRV_RELDATE "Feb 27, 2007" |
25 | 25 | ||
26 | 26 | ||
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 5b71ac78bca2..fa440706fb4a 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c | |||
@@ -1147,7 +1147,7 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) | |||
1147 | } | 1147 | } |
1148 | 1148 | ||
1149 | /* Abnormal error summary/uncommon events handlers. */ | 1149 | /* Abnormal error summary/uncommon events handlers. */ |
1150 | if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SytemError | | 1150 | if (intr_status & (AbnormalIntr | TxFIFOUnderflow | SystemError | |
1151 | TimerInt | TxDied)) | 1151 | TimerInt | TxDied)) |
1152 | netdev_error(dev, intr_status); | 1152 | netdev_error(dev, intr_status); |
1153 | 1153 | ||
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 639e1e6913bf..16b9acdabbe8 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/fsl_devices.h> | 29 | #include <linux/fsl_devices.h> |
30 | #include <linux/ethtool.h> | 30 | #include <linux/ethtool.h> |
31 | #include <linux/mii.h> | 31 | #include <linux/mii.h> |
32 | #include <linux/phy.h> | ||
32 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
33 | 34 | ||
34 | #include <asm/of_platform.h> | 35 | #include <asm/of_platform.h> |
@@ -41,12 +42,13 @@ | |||
41 | #include <asm/ucc_fast.h> | 42 | #include <asm/ucc_fast.h> |
42 | 43 | ||
43 | #include "ucc_geth.h" | 44 | #include "ucc_geth.h" |
44 | #include "ucc_geth_phy.h" | 45 | #include "ucc_geth_mii.h" |
45 | 46 | ||
46 | #undef DEBUG | 47 | #undef DEBUG |
47 | 48 | ||
48 | #define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006" | 49 | #define DRV_DESC "QE UCC Gigabit Ethernet Controller" |
49 | #define DRV_NAME "ucc_geth" | 50 | #define DRV_NAME "ucc_geth" |
51 | #define DRV_VERSION "1.1" | ||
50 | 52 | ||
51 | #define ugeth_printk(level, format, arg...) \ | 53 | #define ugeth_printk(level, format, arg...) \ |
52 | printk(level format "\n", ## arg) | 54 | printk(level format "\n", ## arg) |
@@ -73,22 +75,13 @@ static struct ucc_geth_info ugeth_primary_info = { | |||
73 | .bd_mem_part = MEM_PART_SYSTEM, | 75 | .bd_mem_part = MEM_PART_SYSTEM, |
74 | .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, | 76 | .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, |
75 | .max_rx_buf_length = 1536, | 77 | .max_rx_buf_length = 1536, |
76 | /* FIXME: should be changed in run time for 1G and 100M */ | 78 | /* adjusted at startup if max-speed 1000 */ |
77 | #ifdef CONFIG_UGETH_HAS_GIGA | ||
78 | .urfs = UCC_GETH_URFS_GIGA_INIT, | ||
79 | .urfet = UCC_GETH_URFET_GIGA_INIT, | ||
80 | .urfset = UCC_GETH_URFSET_GIGA_INIT, | ||
81 | .utfs = UCC_GETH_UTFS_GIGA_INIT, | ||
82 | .utfet = UCC_GETH_UTFET_GIGA_INIT, | ||
83 | .utftt = UCC_GETH_UTFTT_GIGA_INIT, | ||
84 | #else | ||
85 | .urfs = UCC_GETH_URFS_INIT, | 79 | .urfs = UCC_GETH_URFS_INIT, |
86 | .urfet = UCC_GETH_URFET_INIT, | 80 | .urfet = UCC_GETH_URFET_INIT, |
87 | .urfset = UCC_GETH_URFSET_INIT, | 81 | .urfset = UCC_GETH_URFSET_INIT, |
88 | .utfs = UCC_GETH_UTFS_INIT, | 82 | .utfs = UCC_GETH_UTFS_INIT, |
89 | .utfet = UCC_GETH_UTFET_INIT, | 83 | .utfet = UCC_GETH_UTFET_INIT, |
90 | .utftt = UCC_GETH_UTFTT_INIT, | 84 | .utftt = UCC_GETH_UTFTT_INIT, |
91 | #endif | ||
92 | .ufpt = 256, | 85 | .ufpt = 256, |
93 | .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, | 86 | .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, |
94 | .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, | 87 | .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, |
@@ -217,70 +210,6 @@ static struct list_head *dequeue(struct list_head *lh) | |||
217 | } | 210 | } |
218 | } | 211 | } |
219 | 212 | ||
220 | static int get_interface_details(enum enet_interface enet_interface, | ||
221 | enum enet_speed *speed, | ||
222 | int *r10m, | ||
223 | int *rmm, | ||
224 | int *rpm, | ||
225 | int *tbi, int *limited_to_full_duplex) | ||
226 | { | ||
227 | /* Analyze enet_interface according to Interface Mode | ||
228 | Configuration table */ | ||
229 | switch (enet_interface) { | ||
230 | case ENET_10_MII: | ||
231 | *speed = ENET_SPEED_10BT; | ||
232 | break; | ||
233 | case ENET_10_RMII: | ||
234 | *speed = ENET_SPEED_10BT; | ||
235 | *r10m = 1; | ||
236 | *rmm = 1; | ||
237 | break; | ||
238 | case ENET_10_RGMII: | ||
239 | *speed = ENET_SPEED_10BT; | ||
240 | *rpm = 1; | ||
241 | *r10m = 1; | ||
242 | *limited_to_full_duplex = 1; | ||
243 | break; | ||
244 | case ENET_100_MII: | ||
245 | *speed = ENET_SPEED_100BT; | ||
246 | break; | ||
247 | case ENET_100_RMII: | ||
248 | *speed = ENET_SPEED_100BT; | ||
249 | *rmm = 1; | ||
250 | break; | ||
251 | case ENET_100_RGMII: | ||
252 | *speed = ENET_SPEED_100BT; | ||
253 | *rpm = 1; | ||
254 | *limited_to_full_duplex = 1; | ||
255 | break; | ||
256 | case ENET_1000_GMII: | ||
257 | *speed = ENET_SPEED_1000BT; | ||
258 | *limited_to_full_duplex = 1; | ||
259 | break; | ||
260 | case ENET_1000_RGMII: | ||
261 | *speed = ENET_SPEED_1000BT; | ||
262 | *rpm = 1; | ||
263 | *limited_to_full_duplex = 1; | ||
264 | break; | ||
265 | case ENET_1000_TBI: | ||
266 | *speed = ENET_SPEED_1000BT; | ||
267 | *tbi = 1; | ||
268 | *limited_to_full_duplex = 1; | ||
269 | break; | ||
270 | case ENET_1000_RTBI: | ||
271 | *speed = ENET_SPEED_1000BT; | ||
272 | *rpm = 1; | ||
273 | *tbi = 1; | ||
274 | *limited_to_full_duplex = 1; | ||
275 | break; | ||
276 | default: | ||
277 | return -EINVAL; | ||
278 | break; | ||
279 | } | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) | 213 | static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) |
285 | { | 214 | { |
286 | struct sk_buff *skb = NULL; | 215 | struct sk_buff *skb = NULL; |
@@ -758,24 +687,6 @@ static void dump_regs(struct ucc_geth_private *ugeth) | |||
758 | ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", | 687 | ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", |
759 | (u32) & ugeth->ug_regs->hafdup, | 688 | (u32) & ugeth->ug_regs->hafdup, |
760 | in_be32(&ugeth->ug_regs->hafdup)); | 689 | in_be32(&ugeth->ug_regs->hafdup)); |
761 | ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x", | ||
762 | (u32) & ugeth->ug_regs->miimng.miimcfg, | ||
763 | in_be32(&ugeth->ug_regs->miimng.miimcfg)); | ||
764 | ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x", | ||
765 | (u32) & ugeth->ug_regs->miimng.miimcom, | ||
766 | in_be32(&ugeth->ug_regs->miimng.miimcom)); | ||
767 | ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x", | ||
768 | (u32) & ugeth->ug_regs->miimng.miimadd, | ||
769 | in_be32(&ugeth->ug_regs->miimng.miimadd)); | ||
770 | ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x", | ||
771 | (u32) & ugeth->ug_regs->miimng.miimcon, | ||
772 | in_be32(&ugeth->ug_regs->miimng.miimcon)); | ||
773 | ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x", | ||
774 | (u32) & ugeth->ug_regs->miimng.miimstat, | ||
775 | in_be32(&ugeth->ug_regs->miimng.miimstat)); | ||
776 | ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x", | ||
777 | (u32) & ugeth->ug_regs->miimng.miimind, | ||
778 | in_be32(&ugeth->ug_regs->miimng.miimind)); | ||
779 | ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", | 690 | ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", |
780 | (u32) & ugeth->ug_regs->ifctl, | 691 | (u32) & ugeth->ug_regs->ifctl, |
781 | in_be32(&ugeth->ug_regs->ifctl)); | 692 | in_be32(&ugeth->ug_regs->ifctl)); |
@@ -1425,27 +1336,6 @@ static int init_mac_station_addr_regs(u8 address_byte_0, | |||
1425 | return 0; | 1336 | return 0; |
1426 | } | 1337 | } |
1427 | 1338 | ||
1428 | static int init_mac_duplex_mode(int full_duplex, | ||
1429 | int limited_to_full_duplex, | ||
1430 | volatile u32 *maccfg2_register) | ||
1431 | { | ||
1432 | u32 value = 0; | ||
1433 | |||
1434 | /* some interfaces must work in full duplex mode */ | ||
1435 | if ((full_duplex == 0) && (limited_to_full_duplex == 1)) | ||
1436 | return -EINVAL; | ||
1437 | |||
1438 | value = in_be32(maccfg2_register); | ||
1439 | |||
1440 | if (full_duplex) | ||
1441 | value |= MACCFG2_FDX; | ||
1442 | else | ||
1443 | value &= ~MACCFG2_FDX; | ||
1444 | |||
1445 | out_be32(maccfg2_register, value); | ||
1446 | return 0; | ||
1447 | } | ||
1448 | |||
1449 | static int init_check_frame_length_mode(int length_check, | 1339 | static int init_check_frame_length_mode(int length_check, |
1450 | volatile u32 *maccfg2_register) | 1340 | volatile u32 *maccfg2_register) |
1451 | { | 1341 | { |
@@ -1477,40 +1367,6 @@ static int init_preamble_length(u8 preamble_length, | |||
1477 | return 0; | 1367 | return 0; |
1478 | } | 1368 | } |
1479 | 1369 | ||
1480 | static int init_mii_management_configuration(int reset_mgmt, | ||
1481 | int preamble_supress, | ||
1482 | volatile u32 *miimcfg_register, | ||
1483 | volatile u32 *miimind_register) | ||
1484 | { | ||
1485 | unsigned int timeout = PHY_INIT_TIMEOUT; | ||
1486 | u32 value = 0; | ||
1487 | |||
1488 | value = in_be32(miimcfg_register); | ||
1489 | if (reset_mgmt) { | ||
1490 | value |= MIIMCFG_RESET_MANAGEMENT; | ||
1491 | out_be32(miimcfg_register, value); | ||
1492 | } | ||
1493 | |||
1494 | value = 0; | ||
1495 | |||
1496 | if (preamble_supress) | ||
1497 | value |= MIIMCFG_NO_PREAMBLE; | ||
1498 | |||
1499 | value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT; | ||
1500 | out_be32(miimcfg_register, value); | ||
1501 | |||
1502 | /* Wait until the bus is free */ | ||
1503 | while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--) | ||
1504 | cpu_relax(); | ||
1505 | |||
1506 | if (timeout <= 0) { | ||
1507 | ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__); | ||
1508 | return -ETIMEDOUT; | ||
1509 | } | ||
1510 | |||
1511 | return 0; | ||
1512 | } | ||
1513 | |||
1514 | static int init_rx_parameters(int reject_broadcast, | 1370 | static int init_rx_parameters(int reject_broadcast, |
1515 | int receive_short_frames, | 1371 | int receive_short_frames, |
1516 | int promiscuous, volatile u32 *upsmr_register) | 1372 | int promiscuous, volatile u32 *upsmr_register) |
@@ -1570,10 +1426,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1570 | struct ucc_geth_info *ug_info; | 1426 | struct ucc_geth_info *ug_info; |
1571 | struct ucc_geth *ug_regs; | 1427 | struct ucc_geth *ug_regs; |
1572 | struct ucc_fast *uf_regs; | 1428 | struct ucc_fast *uf_regs; |
1573 | enum enet_speed speed; | 1429 | int ret_val; |
1574 | int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm = | 1430 | u32 upsmr, maccfg2, tbiBaseAddress; |
1575 | 0, limited_to_full_duplex = 0; | ||
1576 | u32 upsmr, maccfg2, utbipar, tbiBaseAddress; | ||
1577 | u16 value; | 1431 | u16 value; |
1578 | 1432 | ||
1579 | ugeth_vdbg("%s: IN", __FUNCTION__); | 1433 | ugeth_vdbg("%s: IN", __FUNCTION__); |
@@ -1582,24 +1436,13 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1582 | ug_regs = ugeth->ug_regs; | 1436 | ug_regs = ugeth->ug_regs; |
1583 | uf_regs = ugeth->uccf->uf_regs; | 1437 | uf_regs = ugeth->uccf->uf_regs; |
1584 | 1438 | ||
1585 | /* Analyze enet_interface according to Interface Mode Configuration | ||
1586 | table */ | ||
1587 | ret_val = | ||
1588 | get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm, | ||
1589 | &rpm, &tbi, &limited_to_full_duplex); | ||
1590 | if (ret_val != 0) { | ||
1591 | ugeth_err | ||
1592 | ("%s: half duplex not supported in requested configuration.", | ||
1593 | __FUNCTION__); | ||
1594 | return ret_val; | ||
1595 | } | ||
1596 | |||
1597 | /* Set MACCFG2 */ | 1439 | /* Set MACCFG2 */ |
1598 | maccfg2 = in_be32(&ug_regs->maccfg2); | 1440 | maccfg2 = in_be32(&ug_regs->maccfg2); |
1599 | maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; | 1441 | maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; |
1600 | if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT)) | 1442 | if ((ugeth->max_speed == SPEED_10) || |
1443 | (ugeth->max_speed == SPEED_100)) | ||
1601 | maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; | 1444 | maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; |
1602 | else if (speed == ENET_SPEED_1000BT) | 1445 | else if (ugeth->max_speed == SPEED_1000) |
1603 | maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; | 1446 | maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; |
1604 | maccfg2 |= ug_info->padAndCrc; | 1447 | maccfg2 |= ug_info->padAndCrc; |
1605 | out_be32(&ug_regs->maccfg2, maccfg2); | 1448 | out_be32(&ug_regs->maccfg2, maccfg2); |
@@ -1607,54 +1450,39 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1607 | /* Set UPSMR */ | 1450 | /* Set UPSMR */ |
1608 | upsmr = in_be32(&uf_regs->upsmr); | 1451 | upsmr = in_be32(&uf_regs->upsmr); |
1609 | upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); | 1452 | upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); |
1610 | if (rpm) | 1453 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || |
1454 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || | ||
1455 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || | ||
1456 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
1611 | upsmr |= UPSMR_RPM; | 1457 | upsmr |= UPSMR_RPM; |
1612 | if (r10m) | 1458 | switch (ugeth->max_speed) { |
1613 | upsmr |= UPSMR_R10M; | 1459 | case SPEED_10: |
1614 | if (tbi) | 1460 | upsmr |= UPSMR_R10M; |
1461 | /* FALLTHROUGH */ | ||
1462 | case SPEED_100: | ||
1463 | if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI) | ||
1464 | upsmr |= UPSMR_RMM; | ||
1465 | } | ||
1466 | } | ||
1467 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || | ||
1468 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
1615 | upsmr |= UPSMR_TBIM; | 1469 | upsmr |= UPSMR_TBIM; |
1616 | if (rmm) | 1470 | } |
1617 | upsmr |= UPSMR_RMM; | ||
1618 | out_be32(&uf_regs->upsmr, upsmr); | 1471 | out_be32(&uf_regs->upsmr, upsmr); |
1619 | 1472 | ||
1620 | /* Set UTBIPAR */ | ||
1621 | utbipar = in_be32(&ug_regs->utbipar); | ||
1622 | utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; | ||
1623 | if (tbi) | ||
1624 | utbipar |= | ||
1625 | (ug_info->phy_address + | ||
1626 | ugeth->ug_info->uf_info. | ||
1627 | ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; | ||
1628 | else | ||
1629 | utbipar |= | ||
1630 | (0x10 + | ||
1631 | ugeth->ug_info->uf_info. | ||
1632 | ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; | ||
1633 | out_be32(&ug_regs->utbipar, utbipar); | ||
1634 | |||
1635 | /* Disable autonegotiation in tbi mode, because by default it | 1473 | /* Disable autonegotiation in tbi mode, because by default it |
1636 | comes up in autonegotiation mode. */ | 1474 | comes up in autonegotiation mode. */ |
1637 | /* Note that this depends on proper setting in utbipar register. */ | 1475 | /* Note that this depends on proper setting in utbipar register. */ |
1638 | if (tbi) { | 1476 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || |
1477 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
1639 | tbiBaseAddress = in_be32(&ug_regs->utbipar); | 1478 | tbiBaseAddress = in_be32(&ug_regs->utbipar); |
1640 | tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; | 1479 | tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; |
1641 | tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; | 1480 | tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; |
1642 | value = | 1481 | value = ugeth->phydev->bus->read(ugeth->phydev->bus, |
1643 | ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress, | 1482 | (u8) tbiBaseAddress, ENET_TBI_MII_CR); |
1644 | ENET_TBI_MII_CR); | ||
1645 | value &= ~0x1000; /* Turn off autonegotiation */ | 1483 | value &= ~0x1000; /* Turn off autonegotiation */ |
1646 | ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress, | 1484 | ugeth->phydev->bus->write(ugeth->phydev->bus, |
1647 | ENET_TBI_MII_CR, value); | 1485 | (u8) tbiBaseAddress, ENET_TBI_MII_CR, value); |
1648 | } | ||
1649 | |||
1650 | ret_val = init_mac_duplex_mode(1, | ||
1651 | limited_to_full_duplex, | ||
1652 | &ug_regs->maccfg2); | ||
1653 | if (ret_val != 0) { | ||
1654 | ugeth_err | ||
1655 | ("%s: half duplex not supported in requested configuration.", | ||
1656 | __FUNCTION__); | ||
1657 | return ret_val; | ||
1658 | } | 1486 | } |
1659 | 1487 | ||
1660 | init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); | 1488 | init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); |
@@ -1676,76 +1504,88 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
1676 | * function converts those variables into the appropriate | 1504 | * function converts those variables into the appropriate |
1677 | * register values, and can bring down the device if needed. | 1505 | * register values, and can bring down the device if needed. |
1678 | */ | 1506 | */ |
1507 | |||
1679 | static void adjust_link(struct net_device *dev) | 1508 | static void adjust_link(struct net_device *dev) |
1680 | { | 1509 | { |
1681 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 1510 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
1682 | struct ucc_geth *ug_regs; | 1511 | struct ucc_geth *ug_regs; |
1683 | u32 tempval; | 1512 | struct ucc_fast *uf_regs; |
1684 | struct ugeth_mii_info *mii_info = ugeth->mii_info; | 1513 | struct phy_device *phydev = ugeth->phydev; |
1514 | unsigned long flags; | ||
1515 | int new_state = 0; | ||
1685 | 1516 | ||
1686 | ug_regs = ugeth->ug_regs; | 1517 | ug_regs = ugeth->ug_regs; |
1518 | uf_regs = ugeth->uccf->uf_regs; | ||
1687 | 1519 | ||
1688 | if (mii_info->link) { | 1520 | spin_lock_irqsave(&ugeth->lock, flags); |
1521 | |||
1522 | if (phydev->link) { | ||
1523 | u32 tempval = in_be32(&ug_regs->maccfg2); | ||
1524 | u32 upsmr = in_be32(&uf_regs->upsmr); | ||
1689 | /* Now we make sure that we can be in full duplex mode. | 1525 | /* Now we make sure that we can be in full duplex mode. |
1690 | * If not, we operate in half-duplex mode. */ | 1526 | * If not, we operate in half-duplex mode. */ |
1691 | if (mii_info->duplex != ugeth->oldduplex) { | 1527 | if (phydev->duplex != ugeth->oldduplex) { |
1692 | if (!(mii_info->duplex)) { | 1528 | new_state = 1; |
1693 | tempval = in_be32(&ug_regs->maccfg2); | 1529 | if (!(phydev->duplex)) |
1694 | tempval &= ~(MACCFG2_FDX); | 1530 | tempval &= ~(MACCFG2_FDX); |
1695 | out_be32(&ug_regs->maccfg2, tempval); | 1531 | else |
1696 | |||
1697 | ugeth_info("%s: Half Duplex", dev->name); | ||
1698 | } else { | ||
1699 | tempval = in_be32(&ug_regs->maccfg2); | ||
1700 | tempval |= MACCFG2_FDX; | 1532 | tempval |= MACCFG2_FDX; |
1701 | out_be32(&ug_regs->maccfg2, tempval); | 1533 | ugeth->oldduplex = phydev->duplex; |
1702 | |||
1703 | ugeth_info("%s: Full Duplex", dev->name); | ||
1704 | } | ||
1705 | |||
1706 | ugeth->oldduplex = mii_info->duplex; | ||
1707 | } | 1534 | } |
1708 | 1535 | ||
1709 | if (mii_info->speed != ugeth->oldspeed) { | 1536 | if (phydev->speed != ugeth->oldspeed) { |
1710 | switch (mii_info->speed) { | 1537 | new_state = 1; |
1711 | case 1000: | 1538 | switch (phydev->speed) { |
1712 | ugeth->ug_info->enet_interface = ENET_1000_RGMII; | 1539 | case SPEED_1000: |
1540 | tempval = ((tempval & | ||
1541 | ~(MACCFG2_INTERFACE_MODE_MASK)) | | ||
1542 | MACCFG2_INTERFACE_MODE_BYTE); | ||
1713 | break; | 1543 | break; |
1714 | case 100: | 1544 | case SPEED_100: |
1715 | ugeth->ug_info->enet_interface = ENET_100_RGMII; | 1545 | case SPEED_10: |
1716 | break; | 1546 | tempval = ((tempval & |
1717 | case 10: | 1547 | ~(MACCFG2_INTERFACE_MODE_MASK)) | |
1718 | ugeth->ug_info->enet_interface = ENET_10_RGMII; | 1548 | MACCFG2_INTERFACE_MODE_NIBBLE); |
1549 | /* if reduced mode, re-set UPSMR.R10M */ | ||
1550 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || | ||
1551 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || | ||
1552 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || | ||
1553 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
1554 | if (phydev->speed == SPEED_10) | ||
1555 | upsmr |= UPSMR_R10M; | ||
1556 | else | ||
1557 | upsmr &= ~(UPSMR_R10M); | ||
1558 | } | ||
1719 | break; | 1559 | break; |
1720 | default: | 1560 | default: |
1721 | ugeth_warn | 1561 | if (netif_msg_link(ugeth)) |
1722 | ("%s: Ack! Speed (%d) is not 10/100/1000!", | 1562 | ugeth_warn( |
1723 | dev->name, mii_info->speed); | 1563 | "%s: Ack! Speed (%d) is not 10/100/1000!", |
1564 | dev->name, phydev->speed); | ||
1724 | break; | 1565 | break; |
1725 | } | 1566 | } |
1726 | adjust_enet_interface(ugeth); | 1567 | ugeth->oldspeed = phydev->speed; |
1727 | |||
1728 | ugeth_info("%s: Speed %dBT", dev->name, | ||
1729 | mii_info->speed); | ||
1730 | |||
1731 | ugeth->oldspeed = mii_info->speed; | ||
1732 | } | 1568 | } |
1733 | 1569 | ||
1570 | out_be32(&ug_regs->maccfg2, tempval); | ||
1571 | out_be32(&uf_regs->upsmr, upsmr); | ||
1572 | |||
1734 | if (!ugeth->oldlink) { | 1573 | if (!ugeth->oldlink) { |
1735 | ugeth_info("%s: Link is up", dev->name); | 1574 | new_state = 1; |
1736 | ugeth->oldlink = 1; | 1575 | ugeth->oldlink = 1; |
1737 | netif_carrier_on(dev); | ||
1738 | netif_schedule(dev); | 1576 | netif_schedule(dev); |
1739 | } | 1577 | } |
1740 | } else { | 1578 | } else if (ugeth->oldlink) { |
1741 | if (ugeth->oldlink) { | 1579 | new_state = 1; |
1742 | ugeth_info("%s: Link is down", dev->name); | ||
1743 | ugeth->oldlink = 0; | 1580 | ugeth->oldlink = 0; |
1744 | ugeth->oldspeed = 0; | 1581 | ugeth->oldspeed = 0; |
1745 | ugeth->oldduplex = -1; | 1582 | ugeth->oldduplex = -1; |
1746 | netif_carrier_off(dev); | ||
1747 | } | ||
1748 | } | 1583 | } |
1584 | |||
1585 | if (new_state && netif_msg_link(ugeth)) | ||
1586 | phy_print_status(phydev); | ||
1587 | |||
1588 | spin_unlock_irqrestore(&ugeth->lock, flags); | ||
1749 | } | 1589 | } |
1750 | 1590 | ||
1751 | /* Configure the PHY for dev. | 1591 | /* Configure the PHY for dev. |
@@ -1753,102 +1593,40 @@ static void adjust_link(struct net_device *dev) | |||
1753 | */ | 1593 | */ |
1754 | static int init_phy(struct net_device *dev) | 1594 | static int init_phy(struct net_device *dev) |
1755 | { | 1595 | { |
1756 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 1596 | struct ucc_geth_private *priv = netdev_priv(dev); |
1757 | struct phy_info *curphy; | 1597 | struct phy_device *phydev; |
1758 | struct ucc_mii_mng *mii_regs; | 1598 | char phy_id[BUS_ID_SIZE]; |
1759 | struct ugeth_mii_info *mii_info; | ||
1760 | int err; | ||
1761 | 1599 | ||
1762 | mii_regs = &ugeth->ug_regs->miimng; | 1600 | priv->oldlink = 0; |
1601 | priv->oldspeed = 0; | ||
1602 | priv->oldduplex = -1; | ||
1763 | 1603 | ||
1764 | ugeth->oldlink = 0; | 1604 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus, |
1765 | ugeth->oldspeed = 0; | 1605 | priv->ug_info->phy_address); |
1766 | ugeth->oldduplex = -1; | ||
1767 | 1606 | ||
1768 | mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL); | 1607 | phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); |
1769 | 1608 | ||
1770 | if (NULL == mii_info) { | 1609 | if (IS_ERR(phydev)) { |
1771 | ugeth_err("%s: Could not allocate mii_info", dev->name); | 1610 | printk("%s: Could not attach to PHY\n", dev->name); |
1772 | return -ENOMEM; | 1611 | return PTR_ERR(phydev); |
1773 | } | 1612 | } |
1774 | 1613 | ||
1775 | mii_info->mii_regs = mii_regs; | 1614 | phydev->supported &= (ADVERTISED_10baseT_Half | |
1776 | mii_info->speed = SPEED_1000; | ||
1777 | mii_info->duplex = DUPLEX_FULL; | ||
1778 | mii_info->pause = 0; | ||
1779 | mii_info->link = 0; | ||
1780 | |||
1781 | mii_info->advertising = (ADVERTISED_10baseT_Half | | ||
1782 | ADVERTISED_10baseT_Full | | 1615 | ADVERTISED_10baseT_Full | |
1783 | ADVERTISED_100baseT_Half | | 1616 | ADVERTISED_100baseT_Half | |
1784 | ADVERTISED_100baseT_Full | | 1617 | ADVERTISED_100baseT_Full); |
1785 | ADVERTISED_1000baseT_Full); | ||
1786 | mii_info->autoneg = 1; | ||
1787 | 1618 | ||
1788 | mii_info->mii_id = ugeth->ug_info->phy_address; | 1619 | if (priv->max_speed == SPEED_1000) |
1620 | phydev->supported |= ADVERTISED_1000baseT_Full; | ||
1789 | 1621 | ||
1790 | mii_info->dev = dev; | 1622 | phydev->advertising = phydev->supported; |
1791 | 1623 | ||
1792 | mii_info->mdio_read = &read_phy_reg; | 1624 | priv->phydev = phydev; |
1793 | mii_info->mdio_write = &write_phy_reg; | ||
1794 | |||
1795 | spin_lock_init(&mii_info->mdio_lock); | ||
1796 | |||
1797 | ugeth->mii_info = mii_info; | ||
1798 | |||
1799 | spin_lock_irq(&ugeth->lock); | ||
1800 | |||
1801 | /* Set this UCC to be the master of the MII managment */ | ||
1802 | ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); | ||
1803 | |||
1804 | if (init_mii_management_configuration(1, | ||
1805 | ugeth->ug_info-> | ||
1806 | miiPreambleSupress, | ||
1807 | &mii_regs->miimcfg, | ||
1808 | &mii_regs->miimind)) { | ||
1809 | ugeth_err("%s: The MII Bus is stuck!", dev->name); | ||
1810 | err = -1; | ||
1811 | goto bus_fail; | ||
1812 | } | ||
1813 | |||
1814 | spin_unlock_irq(&ugeth->lock); | ||
1815 | |||
1816 | /* get info for this PHY */ | ||
1817 | curphy = get_phy_info(ugeth->mii_info); | ||
1818 | |||
1819 | if (curphy == NULL) { | ||
1820 | ugeth_err("%s: No PHY found", dev->name); | ||
1821 | err = -1; | ||
1822 | goto no_phy; | ||
1823 | } | ||
1824 | |||
1825 | mii_info->phyinfo = curphy; | ||
1826 | |||
1827 | /* Run the commands which initialize the PHY */ | ||
1828 | if (curphy->init) { | ||
1829 | err = curphy->init(ugeth->mii_info); | ||
1830 | if (err) | ||
1831 | goto phy_init_fail; | ||
1832 | } | ||
1833 | 1625 | ||
1834 | return 0; | 1626 | return 0; |
1835 | |||
1836 | phy_init_fail: | ||
1837 | no_phy: | ||
1838 | bus_fail: | ||
1839 | kfree(mii_info); | ||
1840 | |||
1841 | return err; | ||
1842 | } | 1627 | } |
1843 | 1628 | ||
1844 | #ifdef CONFIG_UGETH_TX_ON_DEMOND | ||
1845 | static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth) | ||
1846 | { | ||
1847 | struct ucc_fastransmit_on_demand(ugeth->uccf); | ||
1848 | 1629 | ||
1849 | return 0; | ||
1850 | } | ||
1851 | #endif | ||
1852 | 1630 | ||
1853 | static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) | 1631 | static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) |
1854 | { | 1632 | { |
@@ -2356,6 +2134,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) | |||
2356 | } | 2134 | } |
2357 | for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { | 2135 | for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { |
2358 | bd = ugeth->p_tx_bd_ring[i]; | 2136 | bd = ugeth->p_tx_bd_ring[i]; |
2137 | if (!bd) | ||
2138 | continue; | ||
2359 | for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { | 2139 | for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { |
2360 | if (ugeth->tx_skbuff[i][j]) { | 2140 | if (ugeth->tx_skbuff[i][j]) { |
2361 | dma_unmap_single(NULL, | 2141 | dma_unmap_single(NULL, |
@@ -2487,6 +2267,7 @@ static void ucc_geth_set_multi(struct net_device *dev) | |||
2487 | static void ucc_geth_stop(struct ucc_geth_private *ugeth) | 2267 | static void ucc_geth_stop(struct ucc_geth_private *ugeth) |
2488 | { | 2268 | { |
2489 | struct ucc_geth *ug_regs = ugeth->ug_regs; | 2269 | struct ucc_geth *ug_regs = ugeth->ug_regs; |
2270 | struct phy_device *phydev = ugeth->phydev; | ||
2490 | u32 tempval; | 2271 | u32 tempval; |
2491 | 2272 | ||
2492 | ugeth_vdbg("%s: IN", __FUNCTION__); | 2273 | ugeth_vdbg("%s: IN", __FUNCTION__); |
@@ -2495,8 +2276,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) | |||
2495 | ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); | 2276 | ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); |
2496 | 2277 | ||
2497 | /* Tell the kernel the link is down */ | 2278 | /* Tell the kernel the link is down */ |
2498 | ugeth->mii_info->link = 0; | 2279 | phy_stop(phydev); |
2499 | adjust_link(ugeth->dev); | ||
2500 | 2280 | ||
2501 | /* Mask all interrupts */ | 2281 | /* Mask all interrupts */ |
2502 | out_be32(ugeth->uccf->p_ucce, 0x00000000); | 2282 | out_be32(ugeth->uccf->p_ucce, 0x00000000); |
@@ -2509,50 +2289,24 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) | |||
2509 | tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); | 2289 | tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); |
2510 | out_be32(&ug_regs->maccfg1, tempval); | 2290 | out_be32(&ug_regs->maccfg1, tempval); |
2511 | 2291 | ||
2512 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
2513 | /* Clear any pending interrupts */ | ||
2514 | mii_clear_phy_interrupt(ugeth->mii_info); | ||
2515 | |||
2516 | /* Disable PHY Interrupts */ | ||
2517 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
2518 | MII_INTERRUPT_DISABLED); | ||
2519 | } | ||
2520 | |||
2521 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); | 2292 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); |
2522 | 2293 | ||
2523 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
2524 | free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev); | ||
2525 | } else { | ||
2526 | del_timer_sync(&ugeth->phy_info_timer); | ||
2527 | } | ||
2528 | |||
2529 | ucc_geth_memclean(ugeth); | 2294 | ucc_geth_memclean(ugeth); |
2530 | } | 2295 | } |
2531 | 2296 | ||
2532 | static int ucc_geth_startup(struct ucc_geth_private *ugeth) | 2297 | static int ucc_struct_init(struct ucc_geth_private *ugeth) |
2533 | { | 2298 | { |
2534 | struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; | ||
2535 | struct ucc_geth_init_pram *p_init_enet_pram; | ||
2536 | struct ucc_fast_private *uccf; | ||
2537 | struct ucc_geth_info *ug_info; | 2299 | struct ucc_geth_info *ug_info; |
2538 | struct ucc_fast_info *uf_info; | 2300 | struct ucc_fast_info *uf_info; |
2539 | struct ucc_fast *uf_regs; | 2301 | int i; |
2540 | struct ucc_geth *ug_regs; | ||
2541 | int ret_val = -EINVAL; | ||
2542 | u32 remoder = UCC_GETH_REMODER_INIT; | ||
2543 | u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; | ||
2544 | u32 ifstat, i, j, size, l2qt, l3qt, length; | ||
2545 | u16 temoder = UCC_GETH_TEMODER_INIT; | ||
2546 | u16 test; | ||
2547 | u8 function_code = 0; | ||
2548 | u8 *bd, *endOfRing; | ||
2549 | u8 numThreadsRxNumerical, numThreadsTxNumerical; | ||
2550 | |||
2551 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
2552 | 2302 | ||
2553 | ug_info = ugeth->ug_info; | 2303 | ug_info = ugeth->ug_info; |
2554 | uf_info = &ug_info->uf_info; | 2304 | uf_info = &ug_info->uf_info; |
2555 | 2305 | ||
2306 | /* Create CQs for hash tables */ | ||
2307 | INIT_LIST_HEAD(&ugeth->group_hash_q); | ||
2308 | INIT_LIST_HEAD(&ugeth->ind_hash_q); | ||
2309 | |||
2556 | if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || | 2310 | if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || |
2557 | (uf_info->bd_mem_part == MEM_PART_MURAM))) { | 2311 | (uf_info->bd_mem_part == MEM_PART_MURAM))) { |
2558 | ugeth_err("%s: Bad memory partition value.", __FUNCTION__); | 2312 | ugeth_err("%s: Bad memory partition value.", __FUNCTION__); |
@@ -2647,12 +2401,42 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
2647 | for (i = 0; i < ug_info->numQueuesTx; i++) | 2401 | for (i = 0; i < ug_info->numQueuesTx; i++) |
2648 | uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); | 2402 | uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); |
2649 | /* Initialize the general fast UCC block. */ | 2403 | /* Initialize the general fast UCC block. */ |
2650 | if (ucc_fast_init(uf_info, &uccf)) { | 2404 | if (ucc_fast_init(uf_info, &ugeth->uccf)) { |
2651 | ugeth_err("%s: Failed to init uccf.", __FUNCTION__); | 2405 | ugeth_err("%s: Failed to init uccf.", __FUNCTION__); |
2652 | ucc_geth_memclean(ugeth); | 2406 | ucc_geth_memclean(ugeth); |
2653 | return -ENOMEM; | 2407 | return -ENOMEM; |
2654 | } | 2408 | } |
2655 | ugeth->uccf = uccf; | 2409 | |
2410 | ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth)); | ||
2411 | |||
2412 | return 0; | ||
2413 | } | ||
2414 | |||
2415 | static int ucc_geth_startup(struct ucc_geth_private *ugeth) | ||
2416 | { | ||
2417 | struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; | ||
2418 | struct ucc_geth_init_pram *p_init_enet_pram; | ||
2419 | struct ucc_fast_private *uccf; | ||
2420 | struct ucc_geth_info *ug_info; | ||
2421 | struct ucc_fast_info *uf_info; | ||
2422 | struct ucc_fast *uf_regs; | ||
2423 | struct ucc_geth *ug_regs; | ||
2424 | int ret_val = -EINVAL; | ||
2425 | u32 remoder = UCC_GETH_REMODER_INIT; | ||
2426 | u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; | ||
2427 | u32 ifstat, i, j, size, l2qt, l3qt, length; | ||
2428 | u16 temoder = UCC_GETH_TEMODER_INIT; | ||
2429 | u16 test; | ||
2430 | u8 function_code = 0; | ||
2431 | u8 *bd, *endOfRing; | ||
2432 | u8 numThreadsRxNumerical, numThreadsTxNumerical; | ||
2433 | |||
2434 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
2435 | uccf = ugeth->uccf; | ||
2436 | ug_info = ugeth->ug_info; | ||
2437 | uf_info = &ug_info->uf_info; | ||
2438 | uf_regs = uccf->uf_regs; | ||
2439 | ug_regs = ugeth->ug_regs; | ||
2656 | 2440 | ||
2657 | switch (ug_info->numThreadsRx) { | 2441 | switch (ug_info->numThreadsRx) { |
2658 | case UCC_GETH_NUM_OF_THREADS_1: | 2442 | case UCC_GETH_NUM_OF_THREADS_1: |
@@ -2711,10 +2495,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
2711 | || (ug_info->vlanOperationNonTagged != | 2495 | || (ug_info->vlanOperationNonTagged != |
2712 | UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); | 2496 | UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); |
2713 | 2497 | ||
2714 | uf_regs = uccf->uf_regs; | ||
2715 | ug_regs = (struct ucc_geth *) (uccf->uf_regs); | ||
2716 | ugeth->ug_regs = ug_regs; | ||
2717 | |||
2718 | init_default_reg_vals(&uf_regs->upsmr, | 2498 | init_default_reg_vals(&uf_regs->upsmr, |
2719 | &ug_regs->maccfg1, &ug_regs->maccfg2); | 2499 | &ug_regs->maccfg1, &ug_regs->maccfg2); |
2720 | 2500 | ||
@@ -3177,8 +2957,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
3177 | /* Size varies with number of Rx queues */ | 2957 | /* Size varies with number of Rx queues */ |
3178 | ugeth->rx_irq_coalescing_tbl_offset = | 2958 | ugeth->rx_irq_coalescing_tbl_offset = |
3179 | qe_muram_alloc(ug_info->numQueuesRx * | 2959 | qe_muram_alloc(ug_info->numQueuesRx * |
3180 | sizeof(struct ucc_geth_rx_interrupt_coalescing_entry), | 2960 | sizeof(struct ucc_geth_rx_interrupt_coalescing_entry) |
3181 | UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); | 2961 | + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); |
3182 | if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) { | 2962 | if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) { |
3183 | ugeth_err | 2963 | ugeth_err |
3184 | ("%s: Can not allocate DPRAM memory for" | 2964 | ("%s: Can not allocate DPRAM memory for" |
@@ -3359,13 +3139,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
3359 | for (j = 0; j < NUM_OF_PADDRS; j++) | 3139 | for (j = 0; j < NUM_OF_PADDRS; j++) |
3360 | ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j); | 3140 | ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j); |
3361 | 3141 | ||
3362 | /* Create CQs for hash tables */ | ||
3363 | if (ug_info->maxGroupAddrInHash > 0) { | ||
3364 | INIT_LIST_HEAD(&ugeth->group_hash_q); | ||
3365 | } | ||
3366 | if (ug_info->maxIndAddrInHash > 0) { | ||
3367 | INIT_LIST_HEAD(&ugeth->ind_hash_q); | ||
3368 | } | ||
3369 | p_82xx_addr_filt = | 3142 | p_82xx_addr_filt = |
3370 | (struct ucc_geth_82xx_address_filtering_pram *) ugeth-> | 3143 | (struct ucc_geth_82xx_address_filtering_pram *) ugeth-> |
3371 | p_rx_glbl_pram->addressfiltering; | 3144 | p_rx_glbl_pram->addressfiltering; |
@@ -3562,6 +3335,9 @@ static void ucc_geth_timeout(struct net_device *dev) | |||
3562 | static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) | 3335 | static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) |
3563 | { | 3336 | { |
3564 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 3337 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
3338 | #ifdef CONFIG_UGETH_TX_ON_DEMAND | ||
3339 | struct ucc_fast_private *uccf; | ||
3340 | #endif | ||
3565 | u8 *bd; /* BD pointer */ | 3341 | u8 *bd; /* BD pointer */ |
3566 | u32 bd_status; | 3342 | u32 bd_status; |
3567 | u8 txQ = 0; | 3343 | u8 txQ = 0; |
@@ -3620,6 +3396,10 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
3620 | out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]); | 3396 | out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]); |
3621 | } | 3397 | } |
3622 | 3398 | ||
3399 | #ifdef CONFIG_UGETH_TX_ON_DEMAND | ||
3400 | uccf = ugeth->uccf; | ||
3401 | out_be16(uccf->p_utodr, UCC_FAST_TOD); | ||
3402 | #endif | ||
3623 | spin_unlock_irq(&ugeth->lock); | 3403 | spin_unlock_irq(&ugeth->lock); |
3624 | 3404 | ||
3625 | return 0; | 3405 | return 0; |
@@ -3635,7 +3415,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
3635 | 3415 | ||
3636 | ugeth_vdbg("%s: IN", __FUNCTION__); | 3416 | ugeth_vdbg("%s: IN", __FUNCTION__); |
3637 | 3417 | ||
3638 | spin_lock(&ugeth->lock); | ||
3639 | /* collect received buffers */ | 3418 | /* collect received buffers */ |
3640 | bd = ugeth->rxBd[rxQ]; | 3419 | bd = ugeth->rxBd[rxQ]; |
3641 | 3420 | ||
@@ -3683,7 +3462,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
3683 | skb = get_new_skb(ugeth, bd); | 3462 | skb = get_new_skb(ugeth, bd); |
3684 | if (!skb) { | 3463 | if (!skb) { |
3685 | ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); | 3464 | ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); |
3686 | spin_unlock(&ugeth->lock); | ||
3687 | ugeth->stats.rx_dropped++; | 3465 | ugeth->stats.rx_dropped++; |
3688 | break; | 3466 | break; |
3689 | } | 3467 | } |
@@ -3704,7 +3482,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
3704 | } | 3482 | } |
3705 | 3483 | ||
3706 | ugeth->rxBd[rxQ] = bd; | 3484 | ugeth->rxBd[rxQ] = bd; |
3707 | spin_unlock(&ugeth->lock); | ||
3708 | return howmany; | 3485 | return howmany; |
3709 | } | 3486 | } |
3710 | 3487 | ||
@@ -3756,23 +3533,38 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) | |||
3756 | static int ucc_geth_poll(struct net_device *dev, int *budget) | 3533 | static int ucc_geth_poll(struct net_device *dev, int *budget) |
3757 | { | 3534 | { |
3758 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 3535 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
3536 | struct ucc_geth_info *ug_info; | ||
3537 | struct ucc_fast_private *uccf; | ||
3759 | int howmany; | 3538 | int howmany; |
3760 | int rx_work_limit = *budget; | 3539 | u8 i; |
3761 | u8 rxQ = 0; | 3540 | int rx_work_limit; |
3541 | register u32 uccm; | ||
3542 | |||
3543 | ug_info = ugeth->ug_info; | ||
3762 | 3544 | ||
3545 | rx_work_limit = *budget; | ||
3763 | if (rx_work_limit > dev->quota) | 3546 | if (rx_work_limit > dev->quota) |
3764 | rx_work_limit = dev->quota; | 3547 | rx_work_limit = dev->quota; |
3765 | 3548 | ||
3766 | howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit); | 3549 | howmany = 0; |
3550 | |||
3551 | for (i = 0; i < ug_info->numQueuesRx; i++) { | ||
3552 | howmany += ucc_geth_rx(ugeth, i, rx_work_limit); | ||
3553 | } | ||
3767 | 3554 | ||
3768 | dev->quota -= howmany; | 3555 | dev->quota -= howmany; |
3769 | rx_work_limit -= howmany; | 3556 | rx_work_limit -= howmany; |
3770 | *budget -= howmany; | 3557 | *budget -= howmany; |
3771 | 3558 | ||
3772 | if (rx_work_limit >= 0) | 3559 | if (rx_work_limit > 0) { |
3773 | netif_rx_complete(dev); | 3560 | netif_rx_complete(dev); |
3561 | uccf = ugeth->uccf; | ||
3562 | uccm = in_be32(uccf->p_uccm); | ||
3563 | uccm |= UCCE_RX_EVENTS; | ||
3564 | out_be32(uccf->p_uccm, uccm); | ||
3565 | } | ||
3774 | 3566 | ||
3775 | return (rx_work_limit < 0) ? 1 : 0; | 3567 | return (rx_work_limit > 0) ? 0 : 1; |
3776 | } | 3568 | } |
3777 | #endif /* CONFIG_UGETH_NAPI */ | 3569 | #endif /* CONFIG_UGETH_NAPI */ |
3778 | 3570 | ||
@@ -3782,10 +3574,13 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) | |||
3782 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 3574 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
3783 | struct ucc_fast_private *uccf; | 3575 | struct ucc_fast_private *uccf; |
3784 | struct ucc_geth_info *ug_info; | 3576 | struct ucc_geth_info *ug_info; |
3785 | register u32 ucce = 0; | 3577 | register u32 ucce; |
3786 | register u32 bit_mask = UCCE_RXBF_SINGLE_MASK; | 3578 | register u32 uccm; |
3787 | register u32 tx_mask = UCCE_TXBF_SINGLE_MASK; | 3579 | #ifndef CONFIG_UGETH_NAPI |
3788 | register u8 i; | 3580 | register u32 rx_mask; |
3581 | #endif | ||
3582 | register u32 tx_mask; | ||
3583 | u8 i; | ||
3789 | 3584 | ||
3790 | ugeth_vdbg("%s: IN", __FUNCTION__); | 3585 | ugeth_vdbg("%s: IN", __FUNCTION__); |
3791 | 3586 | ||
@@ -3795,174 +3590,57 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) | |||
3795 | uccf = ugeth->uccf; | 3590 | uccf = ugeth->uccf; |
3796 | ug_info = ugeth->ug_info; | 3591 | ug_info = ugeth->ug_info; |
3797 | 3592 | ||
3798 | do { | 3593 | /* read and clear events */ |
3799 | ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm)); | 3594 | ucce = (u32) in_be32(uccf->p_ucce); |
3800 | 3595 | uccm = (u32) in_be32(uccf->p_uccm); | |
3801 | /* clear event bits for next time */ | 3596 | ucce &= uccm; |
3802 | /* Side effect here is to mask ucce variable | 3597 | out_be32(uccf->p_ucce, ucce); |
3803 | for future processing below. */ | ||
3804 | out_be32(uccf->p_ucce, ucce); /* Clear with ones, | ||
3805 | but only bits in UCCM */ | ||
3806 | |||
3807 | /* We ignore Tx interrupts because Tx confirmation is | ||
3808 | done inside Tx routine */ | ||
3809 | 3598 | ||
3599 | /* check for receive events that require processing */ | ||
3600 | if (ucce & UCCE_RX_EVENTS) { | ||
3601 | #ifdef CONFIG_UGETH_NAPI | ||
3602 | if (netif_rx_schedule_prep(dev)) { | ||
3603 | uccm &= ~UCCE_RX_EVENTS; | ||
3604 | out_be32(uccf->p_uccm, uccm); | ||
3605 | __netif_rx_schedule(dev); | ||
3606 | } | ||
3607 | #else | ||
3608 | rx_mask = UCCE_RXBF_SINGLE_MASK; | ||
3810 | for (i = 0; i < ug_info->numQueuesRx; i++) { | 3609 | for (i = 0; i < ug_info->numQueuesRx; i++) { |
3811 | if (ucce & bit_mask) | 3610 | if (ucce & rx_mask) |
3812 | ucc_geth_rx(ugeth, i, | 3611 | ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]); |
3813 | (int)ugeth->ug_info-> | 3612 | ucce &= ~rx_mask; |
3814 | bdRingLenRx[i]); | 3613 | rx_mask <<= 1; |
3815 | ucce &= ~bit_mask; | ||
3816 | bit_mask <<= 1; | ||
3817 | } | 3614 | } |
3615 | #endif /* CONFIG_UGETH_NAPI */ | ||
3616 | } | ||
3818 | 3617 | ||
3618 | /* Tx event processing */ | ||
3619 | if (ucce & UCCE_TX_EVENTS) { | ||
3620 | spin_lock(&ugeth->lock); | ||
3621 | tx_mask = UCCE_TXBF_SINGLE_MASK; | ||
3819 | for (i = 0; i < ug_info->numQueuesTx; i++) { | 3622 | for (i = 0; i < ug_info->numQueuesTx; i++) { |
3820 | if (ucce & tx_mask) | 3623 | if (ucce & tx_mask) |
3821 | ucc_geth_tx(dev, i); | 3624 | ucc_geth_tx(dev, i); |
3822 | ucce &= ~tx_mask; | 3625 | ucce &= ~tx_mask; |
3823 | tx_mask <<= 1; | 3626 | tx_mask <<= 1; |
3824 | } | 3627 | } |
3628 | spin_unlock(&ugeth->lock); | ||
3629 | } | ||
3825 | 3630 | ||
3826 | /* Exceptions */ | 3631 | /* Errors and other events */ |
3632 | if (ucce & UCCE_OTHER) { | ||
3827 | if (ucce & UCCE_BSY) { | 3633 | if (ucce & UCCE_BSY) { |
3828 | ugeth_vdbg("Got BUSY irq!!!!"); | ||
3829 | ugeth->stats.rx_errors++; | 3634 | ugeth->stats.rx_errors++; |
3830 | ucce &= ~UCCE_BSY; | ||
3831 | } | 3635 | } |
3832 | if (ucce & UCCE_OTHER) { | 3636 | if (ucce & UCCE_TXE) { |
3833 | ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!", | 3637 | ugeth->stats.tx_errors++; |
3834 | ucce); | ||
3835 | ugeth->stats.rx_errors++; | ||
3836 | ucce &= ~ucce; | ||
3837 | } | 3638 | } |
3838 | } | 3639 | } |
3839 | while (ucce); | ||
3840 | |||
3841 | return IRQ_HANDLED; | ||
3842 | } | ||
3843 | |||
3844 | static irqreturn_t phy_interrupt(int irq, void *dev_id) | ||
3845 | { | ||
3846 | struct net_device *dev = (struct net_device *)dev_id; | ||
3847 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
3848 | |||
3849 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
3850 | |||
3851 | /* Clear the interrupt */ | ||
3852 | mii_clear_phy_interrupt(ugeth->mii_info); | ||
3853 | |||
3854 | /* Disable PHY interrupts */ | ||
3855 | mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED); | ||
3856 | |||
3857 | /* Schedule the phy change */ | ||
3858 | schedule_work(&ugeth->tq); | ||
3859 | 3640 | ||
3860 | return IRQ_HANDLED; | 3641 | return IRQ_HANDLED; |
3861 | } | 3642 | } |
3862 | 3643 | ||
3863 | /* Scheduled by the phy_interrupt/timer to handle PHY changes */ | ||
3864 | static void ugeth_phy_change(struct work_struct *work) | ||
3865 | { | ||
3866 | struct ucc_geth_private *ugeth = | ||
3867 | container_of(work, struct ucc_geth_private, tq); | ||
3868 | struct net_device *dev = ugeth->dev; | ||
3869 | struct ucc_geth *ug_regs; | ||
3870 | int result = 0; | ||
3871 | |||
3872 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
3873 | |||
3874 | ug_regs = ugeth->ug_regs; | ||
3875 | |||
3876 | /* Delay to give the PHY a chance to change the | ||
3877 | * register state */ | ||
3878 | msleep(1); | ||
3879 | |||
3880 | /* Update the link, speed, duplex */ | ||
3881 | result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info); | ||
3882 | |||
3883 | /* Adjust the known status as long as the link | ||
3884 | * isn't still coming up */ | ||
3885 | if ((0 == result) || (ugeth->mii_info->link == 0)) | ||
3886 | adjust_link(dev); | ||
3887 | |||
3888 | /* Reenable interrupts, if needed */ | ||
3889 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) | ||
3890 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
3891 | MII_INTERRUPT_ENABLED); | ||
3892 | } | ||
3893 | |||
3894 | /* Called every so often on systems that don't interrupt | ||
3895 | * the core for PHY changes */ | ||
3896 | static void ugeth_phy_timer(unsigned long data) | ||
3897 | { | ||
3898 | struct net_device *dev = (struct net_device *)data; | ||
3899 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
3900 | |||
3901 | schedule_work(&ugeth->tq); | ||
3902 | |||
3903 | mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); | ||
3904 | } | ||
3905 | |||
3906 | /* Keep trying aneg for some time | ||
3907 | * If, after GFAR_AN_TIMEOUT seconds, it has not | ||
3908 | * finished, we switch to forced. | ||
3909 | * Either way, once the process has completed, we either | ||
3910 | * request the interrupt, or switch the timer over to | ||
3911 | * using ugeth_phy_timer to check status */ | ||
3912 | static void ugeth_phy_startup_timer(unsigned long data) | ||
3913 | { | ||
3914 | struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; | ||
3915 | struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev); | ||
3916 | static int secondary = UGETH_AN_TIMEOUT; | ||
3917 | int result; | ||
3918 | |||
3919 | /* Configure the Auto-negotiation */ | ||
3920 | result = mii_info->phyinfo->config_aneg(mii_info); | ||
3921 | |||
3922 | /* If autonegotiation failed to start, and | ||
3923 | * we haven't timed out, reset the timer, and return */ | ||
3924 | if (result && secondary--) { | ||
3925 | mod_timer(&ugeth->phy_info_timer, jiffies + HZ); | ||
3926 | return; | ||
3927 | } else if (result) { | ||
3928 | /* Couldn't start autonegotiation. | ||
3929 | * Try switching to forced */ | ||
3930 | mii_info->autoneg = 0; | ||
3931 | result = mii_info->phyinfo->config_aneg(mii_info); | ||
3932 | |||
3933 | /* Forcing failed! Give up */ | ||
3934 | if (result) { | ||
3935 | ugeth_err("%s: Forcing failed!", mii_info->dev->name); | ||
3936 | return; | ||
3937 | } | ||
3938 | } | ||
3939 | |||
3940 | /* Kill the timer so it can be restarted */ | ||
3941 | del_timer_sync(&ugeth->phy_info_timer); | ||
3942 | |||
3943 | /* Grab the PHY interrupt, if necessary/possible */ | ||
3944 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
3945 | if (request_irq(ugeth->ug_info->phy_interrupt, | ||
3946 | phy_interrupt, IRQF_SHARED, | ||
3947 | "phy_interrupt", mii_info->dev) < 0) { | ||
3948 | ugeth_err("%s: Can't get IRQ %d (PHY)", | ||
3949 | mii_info->dev->name, | ||
3950 | ugeth->ug_info->phy_interrupt); | ||
3951 | } else { | ||
3952 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
3953 | MII_INTERRUPT_ENABLED); | ||
3954 | return; | ||
3955 | } | ||
3956 | } | ||
3957 | |||
3958 | /* Start the timer again, this time in order to | ||
3959 | * handle a change in status */ | ||
3960 | init_timer(&ugeth->phy_info_timer); | ||
3961 | ugeth->phy_info_timer.function = &ugeth_phy_timer; | ||
3962 | ugeth->phy_info_timer.data = (unsigned long)mii_info->dev; | ||
3963 | mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); | ||
3964 | } | ||
3965 | |||
3966 | /* Called when something needs to use the ethernet device */ | 3644 | /* Called when something needs to use the ethernet device */ |
3967 | /* Returns 0 for success. */ | 3645 | /* Returns 0 for success. */ |
3968 | static int ucc_geth_open(struct net_device *dev) | 3646 | static int ucc_geth_open(struct net_device *dev) |
@@ -3979,6 +3657,12 @@ static int ucc_geth_open(struct net_device *dev) | |||
3979 | return -EINVAL; | 3657 | return -EINVAL; |
3980 | } | 3658 | } |
3981 | 3659 | ||
3660 | err = ucc_struct_init(ugeth); | ||
3661 | if (err) { | ||
3662 | ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); | ||
3663 | return err; | ||
3664 | } | ||
3665 | |||
3982 | err = ucc_geth_startup(ugeth); | 3666 | err = ucc_geth_startup(ugeth); |
3983 | if (err) { | 3667 | if (err) { |
3984 | ugeth_err("%s: Cannot configure net device, aborting.", | 3668 | ugeth_err("%s: Cannot configure net device, aborting.", |
@@ -4006,10 +3690,12 @@ static int ucc_geth_open(struct net_device *dev) | |||
4006 | 3690 | ||
4007 | err = init_phy(dev); | 3691 | err = init_phy(dev); |
4008 | if (err) { | 3692 | if (err) { |
4009 | ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name); | 3693 | ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name); |
4010 | return err; | 3694 | return err; |
4011 | } | 3695 | } |
4012 | #ifndef CONFIG_UGETH_NAPI | 3696 | |
3697 | phy_start(ugeth->phydev); | ||
3698 | |||
4013 | err = | 3699 | err = |
4014 | request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, | 3700 | request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, |
4015 | "UCC Geth", dev); | 3701 | "UCC Geth", dev); |
@@ -4019,15 +3705,6 @@ static int ucc_geth_open(struct net_device *dev) | |||
4019 | ucc_geth_stop(ugeth); | 3705 | ucc_geth_stop(ugeth); |
4020 | return err; | 3706 | return err; |
4021 | } | 3707 | } |
4022 | #endif /* CONFIG_UGETH_NAPI */ | ||
4023 | |||
4024 | /* Set up the PHY change work queue */ | ||
4025 | INIT_WORK(&ugeth->tq, ugeth_phy_change); | ||
4026 | |||
4027 | init_timer(&ugeth->phy_info_timer); | ||
4028 | ugeth->phy_info_timer.function = &ugeth_phy_startup_timer; | ||
4029 | ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info; | ||
4030 | mod_timer(&ugeth->phy_info_timer, jiffies + HZ); | ||
4031 | 3708 | ||
4032 | err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); | 3709 | err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); |
4033 | if (err) { | 3710 | if (err) { |
@@ -4050,11 +3727,8 @@ static int ucc_geth_close(struct net_device *dev) | |||
4050 | 3727 | ||
4051 | ucc_geth_stop(ugeth); | 3728 | ucc_geth_stop(ugeth); |
4052 | 3729 | ||
4053 | /* Shutdown the PHY */ | 3730 | phy_disconnect(ugeth->phydev); |
4054 | if (ugeth->mii_info->phyinfo->close) | 3731 | ugeth->phydev = NULL; |
4055 | ugeth->mii_info->phyinfo->close(ugeth->mii_info); | ||
4056 | |||
4057 | kfree(ugeth->mii_info); | ||
4058 | 3732 | ||
4059 | netif_stop_queue(dev); | 3733 | netif_stop_queue(dev); |
4060 | 3734 | ||
@@ -4063,20 +3737,53 @@ static int ucc_geth_close(struct net_device *dev) | |||
4063 | 3737 | ||
4064 | const struct ethtool_ops ucc_geth_ethtool_ops = { }; | 3738 | const struct ethtool_ops ucc_geth_ethtool_ops = { }; |
4065 | 3739 | ||
3740 | static phy_interface_t to_phy_interface(const char *interface_type) | ||
3741 | { | ||
3742 | if (strcasecmp(interface_type, "mii") == 0) | ||
3743 | return PHY_INTERFACE_MODE_MII; | ||
3744 | if (strcasecmp(interface_type, "gmii") == 0) | ||
3745 | return PHY_INTERFACE_MODE_GMII; | ||
3746 | if (strcasecmp(interface_type, "tbi") == 0) | ||
3747 | return PHY_INTERFACE_MODE_TBI; | ||
3748 | if (strcasecmp(interface_type, "rmii") == 0) | ||
3749 | return PHY_INTERFACE_MODE_RMII; | ||
3750 | if (strcasecmp(interface_type, "rgmii") == 0) | ||
3751 | return PHY_INTERFACE_MODE_RGMII; | ||
3752 | if (strcasecmp(interface_type, "rgmii-id") == 0) | ||
3753 | return PHY_INTERFACE_MODE_RGMII_ID; | ||
3754 | if (strcasecmp(interface_type, "rtbi") == 0) | ||
3755 | return PHY_INTERFACE_MODE_RTBI; | ||
3756 | |||
3757 | return PHY_INTERFACE_MODE_MII; | ||
3758 | } | ||
3759 | |||
4066 | static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) | 3760 | static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) |
4067 | { | 3761 | { |
4068 | struct device *device = &ofdev->dev; | 3762 | struct device *device = &ofdev->dev; |
4069 | struct device_node *np = ofdev->node; | 3763 | struct device_node *np = ofdev->node; |
3764 | struct device_node *mdio; | ||
4070 | struct net_device *dev = NULL; | 3765 | struct net_device *dev = NULL; |
4071 | struct ucc_geth_private *ugeth = NULL; | 3766 | struct ucc_geth_private *ugeth = NULL; |
4072 | struct ucc_geth_info *ug_info; | 3767 | struct ucc_geth_info *ug_info; |
4073 | struct resource res; | 3768 | struct resource res; |
4074 | struct device_node *phy; | 3769 | struct device_node *phy; |
4075 | int err, ucc_num, phy_interface; | 3770 | int err, ucc_num, max_speed = 0; |
4076 | static int mii_mng_configured = 0; | ||
4077 | const phandle *ph; | 3771 | const phandle *ph; |
4078 | const unsigned int *prop; | 3772 | const unsigned int *prop; |
4079 | const void *mac_addr; | 3773 | const void *mac_addr; |
3774 | phy_interface_t phy_interface; | ||
3775 | static const int enet_to_speed[] = { | ||
3776 | SPEED_10, SPEED_10, SPEED_10, | ||
3777 | SPEED_100, SPEED_100, SPEED_100, | ||
3778 | SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000, | ||
3779 | }; | ||
3780 | static const phy_interface_t enet_to_phy_interface[] = { | ||
3781 | PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII, | ||
3782 | PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII, | ||
3783 | PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, | ||
3784 | PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, | ||
3785 | PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, | ||
3786 | }; | ||
4080 | 3787 | ||
4081 | ugeth_vdbg("%s: IN", __FUNCTION__); | 3788 | ugeth_vdbg("%s: IN", __FUNCTION__); |
4082 | 3789 | ||
@@ -4087,6 +3794,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4087 | 3794 | ||
4088 | ug_info = &ugeth_info[ucc_num]; | 3795 | ug_info = &ugeth_info[ucc_num]; |
4089 | ug_info->uf_info.ucc_num = ucc_num; | 3796 | ug_info->uf_info.ucc_num = ucc_num; |
3797 | |||
4090 | prop = get_property(np, "rx-clock", NULL); | 3798 | prop = get_property(np, "rx-clock", NULL); |
4091 | ug_info->uf_info.rx_clock = *prop; | 3799 | ug_info->uf_info.rx_clock = *prop; |
4092 | prop = get_property(np, "tx-clock", NULL); | 3800 | prop = get_property(np, "tx-clock", NULL); |
@@ -4104,13 +3812,72 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4104 | if (phy == NULL) | 3812 | if (phy == NULL) |
4105 | return -ENODEV; | 3813 | return -ENODEV; |
4106 | 3814 | ||
3815 | /* set the PHY address */ | ||
4107 | prop = get_property(phy, "reg", NULL); | 3816 | prop = get_property(phy, "reg", NULL); |
3817 | if (prop == NULL) | ||
3818 | return -1; | ||
4108 | ug_info->phy_address = *prop; | 3819 | ug_info->phy_address = *prop; |
4109 | prop = get_property(phy, "interface", NULL); | 3820 | |
4110 | ug_info->enet_interface = *prop; | 3821 | /* get the phy interface type, or default to MII */ |
4111 | ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0); | 3822 | prop = get_property(np, "interface-type", NULL); |
4112 | ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)? | 3823 | if (!prop) { |
4113 | 0:FSL_UGETH_BRD_HAS_PHY_INTR; | 3824 | /* handle interface property present in old trees */ |
3825 | prop = get_property(phy, "interface", NULL); | ||
3826 | if (prop != NULL) | ||
3827 | phy_interface = enet_to_phy_interface[*prop]; | ||
3828 | else | ||
3829 | phy_interface = PHY_INTERFACE_MODE_MII; | ||
3830 | } else { | ||
3831 | phy_interface = to_phy_interface((const char *)prop); | ||
3832 | } | ||
3833 | |||
3834 | /* get speed, or derive from interface */ | ||
3835 | prop = get_property(np, "max-speed", NULL); | ||
3836 | if (!prop) { | ||
3837 | /* handle interface property present in old trees */ | ||
3838 | prop = get_property(phy, "interface", NULL); | ||
3839 | if (prop != NULL) | ||
3840 | max_speed = enet_to_speed[*prop]; | ||
3841 | } else { | ||
3842 | max_speed = *prop; | ||
3843 | } | ||
3844 | if (!max_speed) { | ||
3845 | switch (phy_interface) { | ||
3846 | case PHY_INTERFACE_MODE_GMII: | ||
3847 | case PHY_INTERFACE_MODE_RGMII: | ||
3848 | case PHY_INTERFACE_MODE_RGMII_ID: | ||
3849 | case PHY_INTERFACE_MODE_TBI: | ||
3850 | case PHY_INTERFACE_MODE_RTBI: | ||
3851 | max_speed = SPEED_1000; | ||
3852 | break; | ||
3853 | default: | ||
3854 | max_speed = SPEED_100; | ||
3855 | break; | ||
3856 | } | ||
3857 | } | ||
3858 | |||
3859 | if (max_speed == SPEED_1000) { | ||
3860 | ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT; | ||
3861 | ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT; | ||
3862 | ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT; | ||
3863 | ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT; | ||
3864 | ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT; | ||
3865 | ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; | ||
3866 | } | ||
3867 | |||
3868 | /* Set the bus id */ | ||
3869 | mdio = of_get_parent(phy); | ||
3870 | |||
3871 | if (mdio == NULL) | ||
3872 | return -1; | ||
3873 | |||
3874 | err = of_address_to_resource(mdio, 0, &res); | ||
3875 | of_node_put(mdio); | ||
3876 | |||
3877 | if (err) | ||
3878 | return -1; | ||
3879 | |||
3880 | ug_info->mdio_bus = res.start; | ||
4114 | 3881 | ||
4115 | printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", | 3882 | printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", |
4116 | ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, | 3883 | ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, |
@@ -4122,43 +3889,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4122 | return -ENODEV; | 3889 | return -ENODEV; |
4123 | } | 3890 | } |
4124 | 3891 | ||
4125 | /* FIXME: Work around for early chip rev. */ | ||
4126 | /* There's a bug in initial chip rev(s) in the RGMII ac */ | ||
4127 | /* timing. */ | ||
4128 | /* The following compensates by writing to the reserved */ | ||
4129 | /* QE Port Output Hold Registers (CPOH1?). */ | ||
4130 | prop = get_property(phy, "interface", NULL); | ||
4131 | phy_interface = *prop; | ||
4132 | if ((phy_interface == ENET_1000_RGMII) || | ||
4133 | (phy_interface == ENET_100_RGMII) || | ||
4134 | (phy_interface == ENET_10_RGMII)) { | ||
4135 | struct device_node *soc; | ||
4136 | phys_addr_t immrbase = -1; | ||
4137 | u32 *tmp_reg; | ||
4138 | u32 tmp_val; | ||
4139 | |||
4140 | soc = of_find_node_by_type(NULL, "soc"); | ||
4141 | if (soc) { | ||
4142 | unsigned int size; | ||
4143 | const void *prop = get_property(soc, "reg", &size); | ||
4144 | immrbase = of_translate_address(soc, prop); | ||
4145 | of_node_put(soc); | ||
4146 | }; | ||
4147 | |||
4148 | tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4); | ||
4149 | tmp_val = in_be32(tmp_reg); | ||
4150 | if (ucc_num == 1) | ||
4151 | out_be32(tmp_reg, tmp_val | 0x00003000); | ||
4152 | else if (ucc_num == 2) | ||
4153 | out_be32(tmp_reg, tmp_val | 0x0c000000); | ||
4154 | iounmap(tmp_reg); | ||
4155 | } | ||
4156 | |||
4157 | if (!mii_mng_configured) { | ||
4158 | ucc_set_qe_mux_mii_mng(ucc_num); | ||
4159 | mii_mng_configured = 1; | ||
4160 | } | ||
4161 | |||
4162 | /* Create an ethernet device instance */ | 3892 | /* Create an ethernet device instance */ |
4163 | dev = alloc_etherdev(sizeof(*ugeth)); | 3893 | dev = alloc_etherdev(sizeof(*ugeth)); |
4164 | 3894 | ||
@@ -4192,6 +3922,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4192 | dev->set_multicast_list = ucc_geth_set_multi; | 3922 | dev->set_multicast_list = ucc_geth_set_multi; |
4193 | dev->ethtool_ops = &ucc_geth_ethtool_ops; | 3923 | dev->ethtool_ops = &ucc_geth_ethtool_ops; |
4194 | 3924 | ||
3925 | ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; | ||
3926 | ugeth->phy_interface = phy_interface; | ||
3927 | ugeth->max_speed = max_speed; | ||
3928 | |||
4195 | err = register_netdev(dev); | 3929 | err = register_netdev(dev); |
4196 | if (err) { | 3930 | if (err) { |
4197 | ugeth_err("%s: Cannot register net device, aborting.", | 3931 | ugeth_err("%s: Cannot register net device, aborting.", |
@@ -4200,13 +3934,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
4200 | return err; | 3934 | return err; |
4201 | } | 3935 | } |
4202 | 3936 | ||
4203 | ugeth->ug_info = ug_info; | ||
4204 | ugeth->dev = dev; | ||
4205 | |||
4206 | mac_addr = of_get_mac_address(np); | 3937 | mac_addr = of_get_mac_address(np); |
4207 | if (mac_addr) | 3938 | if (mac_addr) |
4208 | memcpy(dev->dev_addr, mac_addr, 6); | 3939 | memcpy(dev->dev_addr, mac_addr, 6); |
4209 | 3940 | ||
3941 | ugeth->ug_info = ug_info; | ||
3942 | ugeth->dev = dev; | ||
3943 | |||
4210 | return 0; | 3944 | return 0; |
4211 | } | 3945 | } |
4212 | 3946 | ||
@@ -4242,19 +3976,30 @@ static struct of_platform_driver ucc_geth_driver = { | |||
4242 | 3976 | ||
4243 | static int __init ucc_geth_init(void) | 3977 | static int __init ucc_geth_init(void) |
4244 | { | 3978 | { |
4245 | int i; | 3979 | int i, ret; |
3980 | |||
3981 | ret = uec_mdio_init(); | ||
3982 | |||
3983 | if (ret) | ||
3984 | return ret; | ||
4246 | 3985 | ||
4247 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); | 3986 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); |
4248 | for (i = 0; i < 8; i++) | 3987 | for (i = 0; i < 8; i++) |
4249 | memcpy(&(ugeth_info[i]), &ugeth_primary_info, | 3988 | memcpy(&(ugeth_info[i]), &ugeth_primary_info, |
4250 | sizeof(ugeth_primary_info)); | 3989 | sizeof(ugeth_primary_info)); |
4251 | 3990 | ||
4252 | return of_register_platform_driver(&ucc_geth_driver); | 3991 | ret = of_register_platform_driver(&ucc_geth_driver); |
3992 | |||
3993 | if (ret) | ||
3994 | uec_mdio_exit(); | ||
3995 | |||
3996 | return ret; | ||
4253 | } | 3997 | } |
4254 | 3998 | ||
4255 | static void __exit ucc_geth_exit(void) | 3999 | static void __exit ucc_geth_exit(void) |
4256 | { | 4000 | { |
4257 | of_unregister_platform_driver(&ucc_geth_driver); | 4001 | of_unregister_platform_driver(&ucc_geth_driver); |
4002 | uec_mdio_exit(); | ||
4258 | } | 4003 | } |
4259 | 4004 | ||
4260 | module_init(ucc_geth_init); | 4005 | module_init(ucc_geth_init); |
@@ -4262,4 +4007,5 @@ module_exit(ucc_geth_exit); | |||
4262 | 4007 | ||
4263 | MODULE_AUTHOR("Freescale Semiconductor, Inc"); | 4008 | MODULE_AUTHOR("Freescale Semiconductor, Inc"); |
4264 | MODULE_DESCRIPTION(DRV_DESC); | 4009 | MODULE_DESCRIPTION(DRV_DESC); |
4010 | MODULE_VERSION(DRV_VERSION); | ||
4265 | MODULE_LICENSE("GPL"); | 4011 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index a66561253593..a29e1c3ca4b7 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <asm/ucc.h> | 28 | #include <asm/ucc.h> |
29 | #include <asm/ucc_fast.h> | 29 | #include <asm/ucc_fast.h> |
30 | 30 | ||
31 | #include "ucc_geth_mii.h" | ||
32 | |||
31 | #define NUM_TX_QUEUES 8 | 33 | #define NUM_TX_QUEUES 8 |
32 | #define NUM_RX_QUEUES 8 | 34 | #define NUM_RX_QUEUES 8 |
33 | #define NUM_BDS_IN_PREFETCHED_BDS 4 | 35 | #define NUM_BDS_IN_PREFETCHED_BDS 4 |
@@ -36,15 +38,6 @@ | |||
36 | #define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 | 38 | #define ENET_INIT_PARAM_MAX_ENTRIES_RX 9 |
37 | #define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 | 39 | #define ENET_INIT_PARAM_MAX_ENTRIES_TX 8 |
38 | 40 | ||
39 | struct ucc_mii_mng { | ||
40 | u32 miimcfg; /* MII management configuration reg */ | ||
41 | u32 miimcom; /* MII management command reg */ | ||
42 | u32 miimadd; /* MII management address reg */ | ||
43 | u32 miimcon; /* MII management control reg */ | ||
44 | u32 miimstat; /* MII management status reg */ | ||
45 | u32 miimind; /* MII management indication reg */ | ||
46 | } __attribute__ ((packed)); | ||
47 | |||
48 | struct ucc_geth { | 41 | struct ucc_geth { |
49 | struct ucc_fast uccf; | 42 | struct ucc_fast uccf; |
50 | 43 | ||
@@ -53,7 +46,7 @@ struct ucc_geth { | |||
53 | u32 ipgifg; /* interframe gap reg. */ | 46 | u32 ipgifg; /* interframe gap reg. */ |
54 | u32 hafdup; /* half-duplex reg. */ | 47 | u32 hafdup; /* half-duplex reg. */ |
55 | u8 res1[0x10]; | 48 | u8 res1[0x10]; |
56 | struct ucc_mii_mng miimng; /* MII management structure */ | 49 | u8 miimng[0x18]; /* MII management structure moved to _mii.h */ |
57 | u32 ifctl; /* interface control reg */ | 50 | u32 ifctl; /* interface control reg */ |
58 | u32 ifstat; /* interface statux reg */ | 51 | u32 ifstat; /* interface statux reg */ |
59 | u32 macstnaddr1; /* mac station address part 1 reg */ | 52 | u32 macstnaddr1; /* mac station address part 1 reg */ |
@@ -212,6 +205,9 @@ struct ucc_geth { | |||
212 | #define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\ | 205 | #define UCCE_OTHER (UCCE_SCAR | UCCE_GRA | UCCE_CBPR | UCCE_BSY |\ |
213 | UCCE_RXC | UCCE_TXC | UCCE_TXE) | 206 | UCCE_RXC | UCCE_TXC | UCCE_TXE) |
214 | 207 | ||
208 | #define UCCE_RX_EVENTS (UCCE_RXF | UCCE_BSY) | ||
209 | #define UCCE_TX_EVENTS (UCCE_TXB | UCCE_TXE) | ||
210 | |||
215 | /* UCC GETH UPSMR (Protocol Specific Mode Register) */ | 211 | /* UCC GETH UPSMR (Protocol Specific Mode Register) */ |
216 | #define UPSMR_ECM 0x04000000 /* Enable CAM | 212 | #define UPSMR_ECM 0x04000000 /* Enable CAM |
217 | Miss or | 213 | Miss or |
@@ -381,66 +377,6 @@ struct ucc_geth { | |||
381 | #define UCCS_MPD 0x01 /* Magic Packet | 377 | #define UCCS_MPD 0x01 /* Magic Packet |
382 | Detected */ | 378 | Detected */ |
383 | 379 | ||
384 | /* UCC GETH MIIMCFG (MII Management Configuration Register) */ | ||
385 | #define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset | ||
386 | management */ | ||
387 | #define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble | ||
388 | suppress */ | ||
389 | #define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide | ||
390 | << shift */ | ||
391 | #define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* clock divide max val | ||
392 | */ | ||
393 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 /* divide by 2 */ | ||
394 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 /* divide by 4 */ | ||
395 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 /* divide by 6 */ | ||
396 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 /* divide by 8 */ | ||
397 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 /* divide by 10 | ||
398 | */ | ||
399 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 /* divide by 14 | ||
400 | */ | ||
401 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 /* divide by 16 | ||
402 | */ | ||
403 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 /* divide by 20 | ||
404 | */ | ||
405 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 /* divide by 28 | ||
406 | */ | ||
407 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 /* divide by 32 | ||
408 | */ | ||
409 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a /* divide by 48 | ||
410 | */ | ||
411 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b /* divide by 64 | ||
412 | */ | ||
413 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c /* divide by 80 | ||
414 | */ | ||
415 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d /* divide by | ||
416 | 112 */ | ||
417 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e /* divide by | ||
418 | 160 */ | ||
419 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f /* divide by | ||
420 | 224 */ | ||
421 | |||
422 | /* UCC GETH MIIMCOM (MII Management Command Register) */ | ||
423 | #define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ | ||
424 | #define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ | ||
425 | |||
426 | /* UCC GETH MIIMADD (MII Management Address Register) */ | ||
427 | #define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address | ||
428 | << shift */ | ||
429 | #define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register | ||
430 | << shift */ | ||
431 | |||
432 | /* UCC GETH MIIMCON (MII Management Control Register) */ | ||
433 | #define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control | ||
434 | << shift */ | ||
435 | #define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status | ||
436 | << shift */ | ||
437 | |||
438 | /* UCC GETH MIIMIND (MII Management Indicator Register) */ | ||
439 | #define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ | ||
440 | #define MIIMIND_SCAN 0x00000002 /* Scan in | ||
441 | progress */ | ||
442 | #define MIIMIND_BUSY 0x00000001 | ||
443 | |||
444 | /* UCC GETH IFSTAT (Interface Status Register) */ | 380 | /* UCC GETH IFSTAT (Interface Status Register) */ |
445 | #define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive | 381 | #define IFSTAT_EXCESS_DEFER 0x00000200 /* Excessive |
446 | transmission | 382 | transmission |
@@ -931,8 +867,7 @@ struct ucc_geth_hardware_statistics { | |||
931 | #define UCC_GETH_SCHEDULER_ALIGNMENT 4 /* This is a guess */ | 867 | #define UCC_GETH_SCHEDULER_ALIGNMENT 4 /* This is a guess */ |
932 | #define UCC_GETH_TX_STATISTICS_ALIGNMENT 4 /* This is a guess */ | 868 | #define UCC_GETH_TX_STATISTICS_ALIGNMENT 4 /* This is a guess */ |
933 | #define UCC_GETH_RX_STATISTICS_ALIGNMENT 4 /* This is a guess */ | 869 | #define UCC_GETH_RX_STATISTICS_ALIGNMENT 4 /* This is a guess */ |
934 | #define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 4 /* This is a | 870 | #define UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT 64 |
935 | guess */ | ||
936 | #define UCC_GETH_RX_BD_QUEUES_ALIGNMENT 8 /* This is a guess */ | 871 | #define UCC_GETH_RX_BD_QUEUES_ALIGNMENT 8 /* This is a guess */ |
937 | #define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT 128 /* This is a guess */ | 872 | #define UCC_GETH_RX_PREFETCHED_BDS_ALIGNMENT 128 /* This is a guess */ |
938 | #define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 /* This | 873 | #define UCC_GETH_RX_EXTENDED_FILTERING_GLOBAL_PARAMETERS_ALIGNMENT 4 /* This |
@@ -1009,15 +944,6 @@ struct ucc_geth_hardware_statistics { | |||
1009 | register */ | 944 | register */ |
1010 | #define UCC_GETH_MACCFG1_INIT 0 | 945 | #define UCC_GETH_MACCFG1_INIT 0 |
1011 | #define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) | 946 | #define UCC_GETH_MACCFG2_INIT (MACCFG2_RESERVED_1) |
1012 | #define UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT \ | ||
1013 | (MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112) | ||
1014 | |||
1015 | /* Ethernet speed */ | ||
1016 | enum enet_speed { | ||
1017 | ENET_SPEED_10BT, /* 10 Base T */ | ||
1018 | ENET_SPEED_100BT, /* 100 Base T */ | ||
1019 | ENET_SPEED_1000BT /* 1000 Base T */ | ||
1020 | }; | ||
1021 | 947 | ||
1022 | /* Ethernet Address Type. */ | 948 | /* Ethernet Address Type. */ |
1023 | enum enet_addr_type { | 949 | enum enet_addr_type { |
@@ -1026,22 +952,6 @@ enum enet_addr_type { | |||
1026 | ENET_ADDR_TYPE_BROADCAST | 952 | ENET_ADDR_TYPE_BROADCAST |
1027 | }; | 953 | }; |
1028 | 954 | ||
1029 | /* TBI / MII Set Register */ | ||
1030 | enum enet_tbi_mii_reg { | ||
1031 | ENET_TBI_MII_CR = 0x00, /* Control (CR ) */ | ||
1032 | ENET_TBI_MII_SR = 0x01, /* Status (SR ) */ | ||
1033 | ENET_TBI_MII_ANA = 0x04, /* AN advertisement (ANA ) */ | ||
1034 | ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability | ||
1035 | (ANLPBPA) */ | ||
1036 | ENET_TBI_MII_ANEX = 0x06, /* AN expansion (ANEX ) */ | ||
1037 | ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit (ANNPT ) */ | ||
1038 | ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page | ||
1039 | (ANLPANP) */ | ||
1040 | ENET_TBI_MII_EXST = 0x0F, /* Extended status (EXST ) */ | ||
1041 | ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics (JD ) */ | ||
1042 | ENET_TBI_MII_TBICON = 0x11 /* TBI control (TBICON ) */ | ||
1043 | }; | ||
1044 | |||
1045 | /* UCC GETH 82xx Ethernet Address Recognition Location */ | 955 | /* UCC GETH 82xx Ethernet Address Recognition Location */ |
1046 | enum ucc_geth_enet_address_recognition_location { | 956 | enum ucc_geth_enet_address_recognition_location { |
1047 | UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station | 957 | UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_STATION_ADDRESS,/* station |
@@ -1239,8 +1149,7 @@ struct ucc_geth_info { | |||
1239 | u16 pausePeriod; | 1149 | u16 pausePeriod; |
1240 | u16 extensionField; | 1150 | u16 extensionField; |
1241 | u8 phy_address; | 1151 | u8 phy_address; |
1242 | u32 board_flags; | 1152 | u32 mdio_bus; |
1243 | u32 phy_interrupt; | ||
1244 | u8 weightfactor[NUM_TX_QUEUES]; | 1153 | u8 weightfactor[NUM_TX_QUEUES]; |
1245 | u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; | 1154 | u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES]; |
1246 | u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; | 1155 | u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX]; |
@@ -1249,7 +1158,6 @@ struct ucc_geth_info { | |||
1249 | u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; | 1158 | u8 iphoffset[TX_IP_OFFSET_ENTRY_MAX]; |
1250 | u16 bdRingLenTx[NUM_TX_QUEUES]; | 1159 | u16 bdRingLenTx[NUM_TX_QUEUES]; |
1251 | u16 bdRingLenRx[NUM_RX_QUEUES]; | 1160 | u16 bdRingLenRx[NUM_RX_QUEUES]; |
1252 | enum enet_interface enet_interface; | ||
1253 | enum ucc_geth_num_of_station_addresses numStationAddresses; | 1161 | enum ucc_geth_num_of_station_addresses numStationAddresses; |
1254 | enum qe_fltr_largest_external_tbl_lookup_key_size | 1162 | enum qe_fltr_largest_external_tbl_lookup_key_size |
1255 | largestexternallookupkeysize; | 1163 | largestexternallookupkeysize; |
@@ -1326,9 +1234,11 @@ struct ucc_geth_private { | |||
1326 | /* index of the first skb which hasn't been transmitted yet. */ | 1234 | /* index of the first skb which hasn't been transmitted yet. */ |
1327 | u16 skb_dirtytx[NUM_TX_QUEUES]; | 1235 | u16 skb_dirtytx[NUM_TX_QUEUES]; |
1328 | 1236 | ||
1329 | struct work_struct tq; | ||
1330 | struct timer_list phy_info_timer; | ||
1331 | struct ugeth_mii_info *mii_info; | 1237 | struct ugeth_mii_info *mii_info; |
1238 | struct phy_device *phydev; | ||
1239 | phy_interface_t phy_interface; | ||
1240 | int max_speed; | ||
1241 | uint32_t msg_enable; | ||
1332 | int oldspeed; | 1242 | int oldspeed; |
1333 | int oldduplex; | 1243 | int oldduplex; |
1334 | int oldlink; | 1244 | int oldlink; |
diff --git a/drivers/net/ucc_geth_mii.c b/drivers/net/ucc_geth_mii.c new file mode 100644 index 000000000000..73b5a538e8f4 --- /dev/null +++ b/drivers/net/ucc_geth_mii.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * drivers/net/ucc_geth_mii.c | ||
3 | * | ||
4 | * Gianfar Ethernet Driver -- MIIM bus implementation | ||
5 | * Provides Bus interface for MIIM regs | ||
6 | * | ||
7 | * Author: Li Yang | ||
8 | * | ||
9 | * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify it | ||
12 | * under the terms of the GNU General Public License as published by the | ||
13 | * Free Software Foundation; either version 2 of the License, or (at your | ||
14 | * option) any later version. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/sched.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/unistd.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/platform_device.h> | ||
34 | #include <asm/ocp.h> | ||
35 | #include <linux/crc32.h> | ||
36 | #include <linux/mii.h> | ||
37 | #include <linux/phy.h> | ||
38 | #include <linux/fsl_devices.h> | ||
39 | |||
40 | #include <asm/of_platform.h> | ||
41 | #include <asm/io.h> | ||
42 | #include <asm/irq.h> | ||
43 | #include <asm/uaccess.h> | ||
44 | #include <asm/ucc.h> | ||
45 | |||
46 | #include "ucc_geth_mii.h" | ||
47 | #include "ucc_geth.h" | ||
48 | |||
49 | #define DEBUG | ||
50 | #ifdef DEBUG | ||
51 | #define vdbg(format, arg...) printk(KERN_DEBUG , format "\n" , ## arg) | ||
52 | #else | ||
53 | #define vdbg(format, arg...) do {} while(0) | ||
54 | #endif | ||
55 | |||
56 | #define DRV_DESC "QE UCC Ethernet Controller MII Bus" | ||
57 | #define DRV_NAME "fsl-uec_mdio" | ||
58 | |||
59 | /* Write value to the PHY for this device to the register at regnum, */ | ||
60 | /* waiting until the write is done before it returns. All PHY */ | ||
61 | /* configuration has to be done through the master UEC MIIM regs */ | ||
62 | int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value) | ||
63 | { | ||
64 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
65 | |||
66 | /* Setting up the MII Mangement Address Register */ | ||
67 | out_be32(®s->miimadd, | ||
68 | (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); | ||
69 | |||
70 | /* Setting up the MII Mangement Control Register with the value */ | ||
71 | out_be32(®s->miimcon, value); | ||
72 | |||
73 | /* Wait till MII management write is complete */ | ||
74 | while ((in_be32(®s->miimind)) & MIIMIND_BUSY) | ||
75 | cpu_relax(); | ||
76 | |||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | /* Reads from register regnum in the PHY for device dev, */ | ||
81 | /* returning the value. Clears miimcom first. All PHY */ | ||
82 | /* configuration has to be done through the TSEC1 MIIM regs */ | ||
83 | int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum) | ||
84 | { | ||
85 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
86 | u16 value; | ||
87 | |||
88 | /* Setting up the MII Mangement Address Register */ | ||
89 | out_be32(®s->miimadd, | ||
90 | (mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | regnum); | ||
91 | |||
92 | /* Clear miimcom, perform an MII management read cycle */ | ||
93 | out_be32(®s->miimcom, 0); | ||
94 | out_be32(®s->miimcom, MIIMCOM_READ_CYCLE); | ||
95 | |||
96 | /* Wait till MII management write is complete */ | ||
97 | while ((in_be32(®s->miimind)) & (MIIMIND_BUSY | MIIMIND_NOT_VALID)) | ||
98 | cpu_relax(); | ||
99 | |||
100 | /* Read MII management status */ | ||
101 | value = in_be32(®s->miimstat); | ||
102 | |||
103 | return value; | ||
104 | } | ||
105 | |||
106 | /* Reset the MIIM registers, and wait for the bus to free */ | ||
107 | int uec_mdio_reset(struct mii_bus *bus) | ||
108 | { | ||
109 | struct ucc_mii_mng __iomem *regs = (void __iomem *)bus->priv; | ||
110 | unsigned int timeout = PHY_INIT_TIMEOUT; | ||
111 | |||
112 | spin_lock_bh(&bus->mdio_lock); | ||
113 | |||
114 | /* Reset the management interface */ | ||
115 | out_be32(®s->miimcfg, MIIMCFG_RESET_MANAGEMENT); | ||
116 | |||
117 | /* Setup the MII Mgmt clock speed */ | ||
118 | out_be32(®s->miimcfg, MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112); | ||
119 | |||
120 | /* Wait until the bus is free */ | ||
121 | while ((in_be32(®s->miimind) & MIIMIND_BUSY) && timeout--) | ||
122 | cpu_relax(); | ||
123 | |||
124 | spin_unlock_bh(&bus->mdio_lock); | ||
125 | |||
126 | if (timeout <= 0) { | ||
127 | printk(KERN_ERR "%s: The MII Bus is stuck!\n", bus->name); | ||
128 | return -EBUSY; | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | static int uec_mdio_probe(struct of_device *ofdev, const struct of_device_id *match) | ||
135 | { | ||
136 | struct device *device = &ofdev->dev; | ||
137 | struct device_node *np = ofdev->node, *tempnp = NULL; | ||
138 | struct device_node *child = NULL; | ||
139 | struct ucc_mii_mng __iomem *regs; | ||
140 | struct mii_bus *new_bus; | ||
141 | struct resource res; | ||
142 | int k, err = 0; | ||
143 | |||
144 | new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL); | ||
145 | |||
146 | if (NULL == new_bus) | ||
147 | return -ENOMEM; | ||
148 | |||
149 | new_bus->name = "UCC Ethernet Controller MII Bus"; | ||
150 | new_bus->read = &uec_mdio_read; | ||
151 | new_bus->write = &uec_mdio_write; | ||
152 | new_bus->reset = &uec_mdio_reset; | ||
153 | |||
154 | memset(&res, 0, sizeof(res)); | ||
155 | |||
156 | err = of_address_to_resource(np, 0, &res); | ||
157 | if (err) | ||
158 | goto reg_map_fail; | ||
159 | |||
160 | new_bus->id = res.start; | ||
161 | |||
162 | new_bus->irq = kmalloc(32 * sizeof(int), GFP_KERNEL); | ||
163 | |||
164 | if (NULL == new_bus->irq) { | ||
165 | err = -ENOMEM; | ||
166 | goto reg_map_fail; | ||
167 | } | ||
168 | |||
169 | for (k = 0; k < 32; k++) | ||
170 | new_bus->irq[k] = PHY_POLL; | ||
171 | |||
172 | while ((child = of_get_next_child(np, child)) != NULL) { | ||
173 | int irq = irq_of_parse_and_map(child, 0); | ||
174 | if (irq != NO_IRQ) { | ||
175 | const u32 *id = get_property(child, "reg", NULL); | ||
176 | new_bus->irq[*id] = irq; | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /* Set the base address */ | ||
181 | regs = ioremap(res.start, sizeof(struct ucc_mii_mng)); | ||
182 | |||
183 | if (NULL == regs) { | ||
184 | err = -ENOMEM; | ||
185 | goto ioremap_fail; | ||
186 | } | ||
187 | |||
188 | new_bus->priv = (void __force *)regs; | ||
189 | |||
190 | new_bus->dev = device; | ||
191 | dev_set_drvdata(device, new_bus); | ||
192 | |||
193 | /* Read MII management master from device tree */ | ||
194 | while ((tempnp = of_find_compatible_node(tempnp, "network", "ucc_geth")) | ||
195 | != NULL) { | ||
196 | struct resource tempres; | ||
197 | |||
198 | err = of_address_to_resource(tempnp, 0, &tempres); | ||
199 | if (err) | ||
200 | goto bus_register_fail; | ||
201 | |||
202 | /* if our mdio regs fall within this UCC regs range */ | ||
203 | if ((res.start >= tempres.start) && | ||
204 | (res.end <= tempres.end)) { | ||
205 | /* set this UCC to be the MII master */ | ||
206 | const u32 *id = get_property(tempnp, "device-id", NULL); | ||
207 | if (id == NULL) | ||
208 | goto bus_register_fail; | ||
209 | |||
210 | ucc_set_qe_mux_mii_mng(*id - 1); | ||
211 | |||
212 | /* assign the TBI an address which won't | ||
213 | * conflict with the PHYs */ | ||
214 | out_be32(®s->utbipar, UTBIPAR_INIT_TBIPA); | ||
215 | break; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | err = mdiobus_register(new_bus); | ||
220 | if (0 != err) { | ||
221 | printk(KERN_ERR "%s: Cannot register as MDIO bus\n", | ||
222 | new_bus->name); | ||
223 | goto bus_register_fail; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | |||
228 | bus_register_fail: | ||
229 | iounmap(regs); | ||
230 | ioremap_fail: | ||
231 | kfree(new_bus->irq); | ||
232 | reg_map_fail: | ||
233 | kfree(new_bus); | ||
234 | |||
235 | return err; | ||
236 | } | ||
237 | |||
238 | int uec_mdio_remove(struct of_device *ofdev) | ||
239 | { | ||
240 | struct device *device = &ofdev->dev; | ||
241 | struct mii_bus *bus = dev_get_drvdata(device); | ||
242 | |||
243 | mdiobus_unregister(bus); | ||
244 | |||
245 | dev_set_drvdata(device, NULL); | ||
246 | |||
247 | iounmap((void __iomem *)bus->priv); | ||
248 | bus->priv = NULL; | ||
249 | kfree(bus); | ||
250 | |||
251 | return 0; | ||
252 | } | ||
253 | |||
254 | static struct of_device_id uec_mdio_match[] = { | ||
255 | { | ||
256 | .type = "mdio", | ||
257 | .compatible = "ucc_geth_phy", | ||
258 | }, | ||
259 | {}, | ||
260 | }; | ||
261 | |||
262 | MODULE_DEVICE_TABLE(of, uec_mdio_match); | ||
263 | |||
264 | static struct of_platform_driver uec_mdio_driver = { | ||
265 | .name = DRV_NAME, | ||
266 | .probe = uec_mdio_probe, | ||
267 | .remove = uec_mdio_remove, | ||
268 | .match_table = uec_mdio_match, | ||
269 | }; | ||
270 | |||
271 | int __init uec_mdio_init(void) | ||
272 | { | ||
273 | return of_register_platform_driver(&uec_mdio_driver); | ||
274 | } | ||
275 | |||
276 | void __exit uec_mdio_exit(void) | ||
277 | { | ||
278 | of_unregister_platform_driver(&uec_mdio_driver); | ||
279 | } | ||
diff --git a/drivers/net/ucc_geth_mii.h b/drivers/net/ucc_geth_mii.h new file mode 100644 index 000000000000..98430fe0bfc6 --- /dev/null +++ b/drivers/net/ucc_geth_mii.h | |||
@@ -0,0 +1,100 @@ | |||
1 | /* | ||
2 | * drivers/net/ucc_geth_mii.h | ||
3 | * | ||
4 | * Gianfar Ethernet Driver -- MII Management Bus Implementation | ||
5 | * Driver for the MDIO bus controller in the Gianfar register space | ||
6 | * | ||
7 | * Author: Andy Fleming | ||
8 | * Maintainer: Kumar Gala | ||
9 | * | ||
10 | * Copyright (c) 2002-2004 Freescale Semiconductor, Inc. | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify it | ||
13 | * under the terms of the GNU General Public License as published by the | ||
14 | * Free Software Foundation; either version 2 of the License, or (at your | ||
15 | * option) any later version. | ||
16 | * | ||
17 | */ | ||
18 | #ifndef __UEC_MII_H | ||
19 | #define __UEC_MII_H | ||
20 | |||
21 | /* UCC GETH MIIMCFG (MII Management Configuration Register) */ | ||
22 | #define MIIMCFG_RESET_MANAGEMENT 0x80000000 /* Reset | ||
23 | management */ | ||
24 | #define MIIMCFG_NO_PREAMBLE 0x00000010 /* Preamble | ||
25 | suppress */ | ||
26 | #define MIIMCFG_CLOCK_DIVIDE_SHIFT (31 - 31) /* clock divide | ||
27 | << shift */ | ||
28 | #define MIIMCFG_CLOCK_DIVIDE_MAX 0xf /* max clock divide */ | ||
29 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_2 0x00000000 | ||
30 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_4 0x00000001 | ||
31 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_6 0x00000002 | ||
32 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_8 0x00000003 | ||
33 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_10 0x00000004 | ||
34 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_14 0x00000005 | ||
35 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_16 0x00000008 | ||
36 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_20 0x00000006 | ||
37 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_28 0x00000007 | ||
38 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_32 0x00000009 | ||
39 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_48 0x0000000a | ||
40 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_64 0x0000000b | ||
41 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_80 0x0000000c | ||
42 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_112 0x0000000d | ||
43 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_160 0x0000000e | ||
44 | #define MIIMCFG_MANAGEMENT_CLOCK_DIVIDE_BY_224 0x0000000f | ||
45 | |||
46 | /* UCC GETH MIIMCOM (MII Management Command Register) */ | ||
47 | #define MIIMCOM_SCAN_CYCLE 0x00000002 /* Scan cycle */ | ||
48 | #define MIIMCOM_READ_CYCLE 0x00000001 /* Read cycle */ | ||
49 | |||
50 | /* UCC GETH MIIMADD (MII Management Address Register) */ | ||
51 | #define MIIMADD_PHY_ADDRESS_SHIFT (31 - 23) /* PHY Address | ||
52 | << shift */ | ||
53 | #define MIIMADD_PHY_REGISTER_SHIFT (31 - 31) /* PHY Register | ||
54 | << shift */ | ||
55 | |||
56 | /* UCC GETH MIIMCON (MII Management Control Register) */ | ||
57 | #define MIIMCON_PHY_CONTROL_SHIFT (31 - 31) /* PHY Control | ||
58 | << shift */ | ||
59 | #define MIIMCON_PHY_STATUS_SHIFT (31 - 31) /* PHY Status | ||
60 | << shift */ | ||
61 | |||
62 | /* UCC GETH MIIMIND (MII Management Indicator Register) */ | ||
63 | #define MIIMIND_NOT_VALID 0x00000004 /* Not valid */ | ||
64 | #define MIIMIND_SCAN 0x00000002 /* Scan in | ||
65 | progress */ | ||
66 | #define MIIMIND_BUSY 0x00000001 | ||
67 | |||
68 | /* Initial TBI Physical Address */ | ||
69 | #define UTBIPAR_INIT_TBIPA 0x1f | ||
70 | |||
71 | struct ucc_mii_mng { | ||
72 | u32 miimcfg; /* MII management configuration reg */ | ||
73 | u32 miimcom; /* MII management command reg */ | ||
74 | u32 miimadd; /* MII management address reg */ | ||
75 | u32 miimcon; /* MII management control reg */ | ||
76 | u32 miimstat; /* MII management status reg */ | ||
77 | u32 miimind; /* MII management indication reg */ | ||
78 | u8 notcare[28]; /* Space holder */ | ||
79 | u32 utbipar; /* TBI phy address reg */ | ||
80 | } __attribute__ ((packed)); | ||
81 | |||
82 | /* TBI / MII Set Register */ | ||
83 | enum enet_tbi_mii_reg { | ||
84 | ENET_TBI_MII_CR = 0x00, /* Control */ | ||
85 | ENET_TBI_MII_SR = 0x01, /* Status */ | ||
86 | ENET_TBI_MII_ANA = 0x04, /* AN advertisement */ | ||
87 | ENET_TBI_MII_ANLPBPA = 0x05, /* AN link partner base page ability */ | ||
88 | ENET_TBI_MII_ANEX = 0x06, /* AN expansion */ | ||
89 | ENET_TBI_MII_ANNPT = 0x07, /* AN next page transmit */ | ||
90 | ENET_TBI_MII_ANLPANP = 0x08, /* AN link partner ability next page */ | ||
91 | ENET_TBI_MII_EXST = 0x0F, /* Extended status */ | ||
92 | ENET_TBI_MII_JD = 0x10, /* Jitter diagnostics */ | ||
93 | ENET_TBI_MII_TBICON = 0x11 /* TBI control */ | ||
94 | }; | ||
95 | |||
96 | int uec_mdio_read(struct mii_bus *bus, int mii_id, int regnum); | ||
97 | int uec_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value); | ||
98 | int __init uec_mdio_init(void); | ||
99 | void __exit uec_mdio_exit(void); | ||
100 | #endif /* __UEC_MII_H */ | ||
diff --git a/drivers/net/ucc_geth_phy.c b/drivers/net/ucc_geth_phy.c deleted file mode 100644 index 9373d895b9ec..000000000000 --- a/drivers/net/ucc_geth_phy.c +++ /dev/null | |||
@@ -1,785 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | ||
3 | * | ||
4 | * Author: Shlomi Gridish <gridish@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * UCC GETH Driver -- PHY handling | ||
8 | * | ||
9 | * Changelog: | ||
10 | * Jun 28, 2006 Li Yang <LeoLi@freescale.com> | ||
11 | * - Rearrange code and style fixes | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/string.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/init.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include <linux/netdevice.h> | ||
28 | #include <linux/etherdevice.h> | ||
29 | #include <linux/skbuff.h> | ||
30 | #include <linux/spinlock.h> | ||
31 | #include <linux/mm.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/version.h> | ||
34 | #include <linux/crc32.h> | ||
35 | #include <linux/mii.h> | ||
36 | #include <linux/ethtool.h> | ||
37 | |||
38 | #include <asm/io.h> | ||
39 | #include <asm/irq.h> | ||
40 | #include <asm/uaccess.h> | ||
41 | |||
42 | #include "ucc_geth.h" | ||
43 | #include "ucc_geth_phy.h" | ||
44 | |||
45 | #define ugphy_printk(level, format, arg...) \ | ||
46 | printk(level format "\n", ## arg) | ||
47 | |||
48 | #define ugphy_dbg(format, arg...) \ | ||
49 | ugphy_printk(KERN_DEBUG, format , ## arg) | ||
50 | #define ugphy_err(format, arg...) \ | ||
51 | ugphy_printk(KERN_ERR, format , ## arg) | ||
52 | #define ugphy_info(format, arg...) \ | ||
53 | ugphy_printk(KERN_INFO, format , ## arg) | ||
54 | #define ugphy_warn(format, arg...) \ | ||
55 | ugphy_printk(KERN_WARNING, format , ## arg) | ||
56 | |||
57 | #ifdef UGETH_VERBOSE_DEBUG | ||
58 | #define ugphy_vdbg ugphy_dbg | ||
59 | #else | ||
60 | #define ugphy_vdbg(fmt, args...) do { } while (0) | ||
61 | #endif /* UGETH_VERBOSE_DEBUG */ | ||
62 | |||
63 | static void config_genmii_advert(struct ugeth_mii_info *mii_info); | ||
64 | static void genmii_setup_forced(struct ugeth_mii_info *mii_info); | ||
65 | static void genmii_restart_aneg(struct ugeth_mii_info *mii_info); | ||
66 | static int gbit_config_aneg(struct ugeth_mii_info *mii_info); | ||
67 | static int genmii_config_aneg(struct ugeth_mii_info *mii_info); | ||
68 | static int genmii_update_link(struct ugeth_mii_info *mii_info); | ||
69 | static int genmii_read_status(struct ugeth_mii_info *mii_info); | ||
70 | |||
71 | static u16 ucc_geth_phy_read(struct ugeth_mii_info *mii_info, u16 regnum) | ||
72 | { | ||
73 | u16 retval; | ||
74 | unsigned long flags; | ||
75 | |||
76 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
77 | |||
78 | spin_lock_irqsave(&mii_info->mdio_lock, flags); | ||
79 | retval = mii_info->mdio_read(mii_info->dev, mii_info->mii_id, regnum); | ||
80 | spin_unlock_irqrestore(&mii_info->mdio_lock, flags); | ||
81 | |||
82 | return retval; | ||
83 | } | ||
84 | |||
85 | static void ucc_geth_phy_write(struct ugeth_mii_info *mii_info, u16 regnum, u16 val) | ||
86 | { | ||
87 | unsigned long flags; | ||
88 | |||
89 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
90 | |||
91 | spin_lock_irqsave(&mii_info->mdio_lock, flags); | ||
92 | mii_info->mdio_write(mii_info->dev, mii_info->mii_id, regnum, val); | ||
93 | spin_unlock_irqrestore(&mii_info->mdio_lock, flags); | ||
94 | } | ||
95 | |||
96 | /* Write value to the PHY for this device to the register at regnum, */ | ||
97 | /* waiting until the write is done before it returns. All PHY */ | ||
98 | /* configuration has to be done through the TSEC1 MIIM regs */ | ||
99 | void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value) | ||
100 | { | ||
101 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
102 | struct ucc_mii_mng *mii_regs; | ||
103 | enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; | ||
104 | u32 tmp_reg; | ||
105 | |||
106 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
107 | |||
108 | spin_lock_irq(&ugeth->lock); | ||
109 | |||
110 | mii_regs = ugeth->mii_info->mii_regs; | ||
111 | |||
112 | /* Set this UCC to be the master of the MII managment */ | ||
113 | ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); | ||
114 | |||
115 | /* Stop the MII management read cycle */ | ||
116 | out_be32(&mii_regs->miimcom, 0); | ||
117 | /* Setting up the MII Mangement Address Register */ | ||
118 | tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; | ||
119 | out_be32(&mii_regs->miimadd, tmp_reg); | ||
120 | |||
121 | /* Setting up the MII Mangement Control Register with the value */ | ||
122 | out_be32(&mii_regs->miimcon, (u32) value); | ||
123 | |||
124 | /* Wait till MII management write is complete */ | ||
125 | while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) | ||
126 | cpu_relax(); | ||
127 | |||
128 | spin_unlock_irq(&ugeth->lock); | ||
129 | |||
130 | udelay(10000); | ||
131 | } | ||
132 | |||
133 | /* Reads from register regnum in the PHY for device dev, */ | ||
134 | /* returning the value. Clears miimcom first. All PHY */ | ||
135 | /* configuration has to be done through the TSEC1 MIIM regs */ | ||
136 | int read_phy_reg(struct net_device *dev, int mii_id, int regnum) | ||
137 | { | ||
138 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
139 | struct ucc_mii_mng *mii_regs; | ||
140 | enum enet_tbi_mii_reg mii_reg = (enum enet_tbi_mii_reg) regnum; | ||
141 | u32 tmp_reg; | ||
142 | u16 value; | ||
143 | |||
144 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
145 | |||
146 | spin_lock_irq(&ugeth->lock); | ||
147 | |||
148 | mii_regs = ugeth->mii_info->mii_regs; | ||
149 | |||
150 | /* Setting up the MII Mangement Address Register */ | ||
151 | tmp_reg = ((u32) mii_id << MIIMADD_PHY_ADDRESS_SHIFT) | mii_reg; | ||
152 | out_be32(&mii_regs->miimadd, tmp_reg); | ||
153 | |||
154 | /* Perform an MII management read cycle */ | ||
155 | out_be32(&mii_regs->miimcom, MIIMCOM_READ_CYCLE); | ||
156 | |||
157 | /* Wait till MII management write is complete */ | ||
158 | while ((in_be32(&mii_regs->miimind)) & MIIMIND_BUSY) | ||
159 | cpu_relax(); | ||
160 | |||
161 | udelay(10000); | ||
162 | |||
163 | /* Read MII management status */ | ||
164 | value = (u16) in_be32(&mii_regs->miimstat); | ||
165 | out_be32(&mii_regs->miimcom, 0); | ||
166 | if (value == 0xffff) | ||
167 | ugphy_warn("read wrong value : mii_id %d,mii_reg %d, base %08x", | ||
168 | mii_id, mii_reg, (u32) & (mii_regs->miimcfg)); | ||
169 | |||
170 | spin_unlock_irq(&ugeth->lock); | ||
171 | |||
172 | return (value); | ||
173 | } | ||
174 | |||
175 | void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info) | ||
176 | { | ||
177 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
178 | |||
179 | if (mii_info->phyinfo->ack_interrupt) | ||
180 | mii_info->phyinfo->ack_interrupt(mii_info); | ||
181 | } | ||
182 | |||
183 | void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, | ||
184 | u32 interrupts) | ||
185 | { | ||
186 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
187 | |||
188 | mii_info->interrupts = interrupts; | ||
189 | if (mii_info->phyinfo->config_intr) | ||
190 | mii_info->phyinfo->config_intr(mii_info); | ||
191 | } | ||
192 | |||
193 | /* Writes MII_ADVERTISE with the appropriate values, after | ||
194 | * sanitizing advertise to make sure only supported features | ||
195 | * are advertised | ||
196 | */ | ||
197 | static void config_genmii_advert(struct ugeth_mii_info *mii_info) | ||
198 | { | ||
199 | u32 advertise; | ||
200 | u16 adv; | ||
201 | |||
202 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
203 | |||
204 | /* Only allow advertising what this PHY supports */ | ||
205 | mii_info->advertising &= mii_info->phyinfo->features; | ||
206 | advertise = mii_info->advertising; | ||
207 | |||
208 | /* Setup standard advertisement */ | ||
209 | adv = ucc_geth_phy_read(mii_info, MII_ADVERTISE); | ||
210 | adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); | ||
211 | if (advertise & ADVERTISED_10baseT_Half) | ||
212 | adv |= ADVERTISE_10HALF; | ||
213 | if (advertise & ADVERTISED_10baseT_Full) | ||
214 | adv |= ADVERTISE_10FULL; | ||
215 | if (advertise & ADVERTISED_100baseT_Half) | ||
216 | adv |= ADVERTISE_100HALF; | ||
217 | if (advertise & ADVERTISED_100baseT_Full) | ||
218 | adv |= ADVERTISE_100FULL; | ||
219 | ucc_geth_phy_write(mii_info, MII_ADVERTISE, adv); | ||
220 | } | ||
221 | |||
222 | static void genmii_setup_forced(struct ugeth_mii_info *mii_info) | ||
223 | { | ||
224 | u16 ctrl; | ||
225 | u32 features = mii_info->phyinfo->features; | ||
226 | |||
227 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
228 | |||
229 | ctrl = ucc_geth_phy_read(mii_info, MII_BMCR); | ||
230 | |||
231 | ctrl &= | ||
232 | ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE); | ||
233 | ctrl |= BMCR_RESET; | ||
234 | |||
235 | switch (mii_info->speed) { | ||
236 | case SPEED_1000: | ||
237 | if (features & (SUPPORTED_1000baseT_Half | ||
238 | | SUPPORTED_1000baseT_Full)) { | ||
239 | ctrl |= BMCR_SPEED1000; | ||
240 | break; | ||
241 | } | ||
242 | mii_info->speed = SPEED_100; | ||
243 | case SPEED_100: | ||
244 | if (features & (SUPPORTED_100baseT_Half | ||
245 | | SUPPORTED_100baseT_Full)) { | ||
246 | ctrl |= BMCR_SPEED100; | ||
247 | break; | ||
248 | } | ||
249 | mii_info->speed = SPEED_10; | ||
250 | case SPEED_10: | ||
251 | if (features & (SUPPORTED_10baseT_Half | ||
252 | | SUPPORTED_10baseT_Full)) | ||
253 | break; | ||
254 | default: /* Unsupported speed! */ | ||
255 | ugphy_err("%s: Bad speed!", mii_info->dev->name); | ||
256 | break; | ||
257 | } | ||
258 | |||
259 | ucc_geth_phy_write(mii_info, MII_BMCR, ctrl); | ||
260 | } | ||
261 | |||
262 | /* Enable and Restart Autonegotiation */ | ||
263 | static void genmii_restart_aneg(struct ugeth_mii_info *mii_info) | ||
264 | { | ||
265 | u16 ctl; | ||
266 | |||
267 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
268 | |||
269 | ctl = ucc_geth_phy_read(mii_info, MII_BMCR); | ||
270 | ctl |= (BMCR_ANENABLE | BMCR_ANRESTART); | ||
271 | ucc_geth_phy_write(mii_info, MII_BMCR, ctl); | ||
272 | } | ||
273 | |||
274 | static int gbit_config_aneg(struct ugeth_mii_info *mii_info) | ||
275 | { | ||
276 | u16 adv; | ||
277 | u32 advertise; | ||
278 | |||
279 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
280 | |||
281 | if (mii_info->autoneg) { | ||
282 | /* Configure the ADVERTISE register */ | ||
283 | config_genmii_advert(mii_info); | ||
284 | advertise = mii_info->advertising; | ||
285 | |||
286 | adv = ucc_geth_phy_read(mii_info, MII_1000BASETCONTROL); | ||
287 | adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP | | ||
288 | MII_1000BASETCONTROL_HALFDUPLEXCAP); | ||
289 | if (advertise & SUPPORTED_1000baseT_Half) | ||
290 | adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP; | ||
291 | if (advertise & SUPPORTED_1000baseT_Full) | ||
292 | adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP; | ||
293 | ucc_geth_phy_write(mii_info, MII_1000BASETCONTROL, adv); | ||
294 | |||
295 | /* Start/Restart aneg */ | ||
296 | genmii_restart_aneg(mii_info); | ||
297 | } else | ||
298 | genmii_setup_forced(mii_info); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int genmii_config_aneg(struct ugeth_mii_info *mii_info) | ||
304 | { | ||
305 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
306 | |||
307 | if (mii_info->autoneg) { | ||
308 | config_genmii_advert(mii_info); | ||
309 | genmii_restart_aneg(mii_info); | ||
310 | } else | ||
311 | genmii_setup_forced(mii_info); | ||
312 | |||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int genmii_update_link(struct ugeth_mii_info *mii_info) | ||
317 | { | ||
318 | u16 status; | ||
319 | |||
320 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
321 | |||
322 | /* Do a fake read */ | ||
323 | ucc_geth_phy_read(mii_info, MII_BMSR); | ||
324 | |||
325 | /* Read link and autonegotiation status */ | ||
326 | status = ucc_geth_phy_read(mii_info, MII_BMSR); | ||
327 | if ((status & BMSR_LSTATUS) == 0) | ||
328 | mii_info->link = 0; | ||
329 | else | ||
330 | mii_info->link = 1; | ||
331 | |||
332 | /* If we are autonegotiating, and not done, | ||
333 | * return an error */ | ||
334 | if (mii_info->autoneg && !(status & BMSR_ANEGCOMPLETE)) | ||
335 | return -EAGAIN; | ||
336 | |||
337 | return 0; | ||
338 | } | ||
339 | |||
340 | static int genmii_read_status(struct ugeth_mii_info *mii_info) | ||
341 | { | ||
342 | u16 status; | ||
343 | int err; | ||
344 | |||
345 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
346 | |||
347 | /* Update the link, but return if there | ||
348 | * was an error */ | ||
349 | err = genmii_update_link(mii_info); | ||
350 | if (err) | ||
351 | return err; | ||
352 | |||
353 | if (mii_info->autoneg) { | ||
354 | status = ucc_geth_phy_read(mii_info, MII_LPA); | ||
355 | |||
356 | if (status & (LPA_10FULL | LPA_100FULL)) | ||
357 | mii_info->duplex = DUPLEX_FULL; | ||
358 | else | ||
359 | mii_info->duplex = DUPLEX_HALF; | ||
360 | if (status & (LPA_100FULL | LPA_100HALF)) | ||
361 | mii_info->speed = SPEED_100; | ||
362 | else | ||
363 | mii_info->speed = SPEED_10; | ||
364 | mii_info->pause = 0; | ||
365 | } | ||
366 | /* On non-aneg, we assume what we put in BMCR is the speed, | ||
367 | * though magic-aneg shouldn't prevent this case from occurring | ||
368 | */ | ||
369 | |||
370 | return 0; | ||
371 | } | ||
372 | |||
373 | static int marvell_init(struct ugeth_mii_info *mii_info) | ||
374 | { | ||
375 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
376 | |||
377 | ucc_geth_phy_write(mii_info, 0x14, 0x0cd2); | ||
378 | ucc_geth_phy_write(mii_info, 0x1b, | ||
379 | (ucc_geth_phy_read(mii_info, 0x1b) & ~0x000f) | 0x000b); | ||
380 | ucc_geth_phy_write(mii_info, MII_BMCR, | ||
381 | ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); | ||
382 | msleep(4000); | ||
383 | |||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static int marvell_config_aneg(struct ugeth_mii_info *mii_info) | ||
388 | { | ||
389 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
390 | |||
391 | /* The Marvell PHY has an errata which requires | ||
392 | * that certain registers get written in order | ||
393 | * to restart autonegotiation */ | ||
394 | ucc_geth_phy_write(mii_info, MII_BMCR, BMCR_RESET); | ||
395 | |||
396 | ucc_geth_phy_write(mii_info, 0x1d, 0x1f); | ||
397 | ucc_geth_phy_write(mii_info, 0x1e, 0x200c); | ||
398 | ucc_geth_phy_write(mii_info, 0x1d, 0x5); | ||
399 | ucc_geth_phy_write(mii_info, 0x1e, 0); | ||
400 | ucc_geth_phy_write(mii_info, 0x1e, 0x100); | ||
401 | |||
402 | gbit_config_aneg(mii_info); | ||
403 | |||
404 | return 0; | ||
405 | } | ||
406 | |||
407 | static int marvell_read_status(struct ugeth_mii_info *mii_info) | ||
408 | { | ||
409 | u16 status; | ||
410 | int err; | ||
411 | |||
412 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
413 | |||
414 | /* Update the link, but return if there | ||
415 | * was an error */ | ||
416 | err = genmii_update_link(mii_info); | ||
417 | if (err) | ||
418 | return err; | ||
419 | |||
420 | /* If the link is up, read the speed and duplex */ | ||
421 | /* If we aren't autonegotiating, assume speeds | ||
422 | * are as set */ | ||
423 | if (mii_info->autoneg && mii_info->link) { | ||
424 | int speed; | ||
425 | status = ucc_geth_phy_read(mii_info, MII_M1011_PHY_SPEC_STATUS); | ||
426 | |||
427 | /* Get the duplexity */ | ||
428 | if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX) | ||
429 | mii_info->duplex = DUPLEX_FULL; | ||
430 | else | ||
431 | mii_info->duplex = DUPLEX_HALF; | ||
432 | |||
433 | /* Get the speed */ | ||
434 | speed = status & MII_M1011_PHY_SPEC_STATUS_SPD_MASK; | ||
435 | switch (speed) { | ||
436 | case MII_M1011_PHY_SPEC_STATUS_1000: | ||
437 | mii_info->speed = SPEED_1000; | ||
438 | break; | ||
439 | case MII_M1011_PHY_SPEC_STATUS_100: | ||
440 | mii_info->speed = SPEED_100; | ||
441 | break; | ||
442 | default: | ||
443 | mii_info->speed = SPEED_10; | ||
444 | break; | ||
445 | } | ||
446 | mii_info->pause = 0; | ||
447 | } | ||
448 | |||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int marvell_ack_interrupt(struct ugeth_mii_info *mii_info) | ||
453 | { | ||
454 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
455 | |||
456 | /* Clear the interrupts by reading the reg */ | ||
457 | ucc_geth_phy_read(mii_info, MII_M1011_IEVENT); | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int marvell_config_intr(struct ugeth_mii_info *mii_info) | ||
463 | { | ||
464 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
465 | |||
466 | if (mii_info->interrupts == MII_INTERRUPT_ENABLED) | ||
467 | ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_INIT); | ||
468 | else | ||
469 | ucc_geth_phy_write(mii_info, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR); | ||
470 | |||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int cis820x_init(struct ugeth_mii_info *mii_info) | ||
475 | { | ||
476 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
477 | |||
478 | ucc_geth_phy_write(mii_info, MII_CIS8201_AUX_CONSTAT, | ||
479 | MII_CIS8201_AUXCONSTAT_INIT); | ||
480 | ucc_geth_phy_write(mii_info, MII_CIS8201_EXT_CON1, MII_CIS8201_EXTCON1_INIT); | ||
481 | |||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | static int cis820x_read_status(struct ugeth_mii_info *mii_info) | ||
486 | { | ||
487 | u16 status; | ||
488 | int err; | ||
489 | |||
490 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
491 | |||
492 | /* Update the link, but return if there | ||
493 | * was an error */ | ||
494 | err = genmii_update_link(mii_info); | ||
495 | if (err) | ||
496 | return err; | ||
497 | |||
498 | /* If the link is up, read the speed and duplex */ | ||
499 | /* If we aren't autonegotiating, assume speeds | ||
500 | * are as set */ | ||
501 | if (mii_info->autoneg && mii_info->link) { | ||
502 | int speed; | ||
503 | |||
504 | status = ucc_geth_phy_read(mii_info, MII_CIS8201_AUX_CONSTAT); | ||
505 | if (status & MII_CIS8201_AUXCONSTAT_DUPLEX) | ||
506 | mii_info->duplex = DUPLEX_FULL; | ||
507 | else | ||
508 | mii_info->duplex = DUPLEX_HALF; | ||
509 | |||
510 | speed = status & MII_CIS8201_AUXCONSTAT_SPEED; | ||
511 | |||
512 | switch (speed) { | ||
513 | case MII_CIS8201_AUXCONSTAT_GBIT: | ||
514 | mii_info->speed = SPEED_1000; | ||
515 | break; | ||
516 | case MII_CIS8201_AUXCONSTAT_100: | ||
517 | mii_info->speed = SPEED_100; | ||
518 | break; | ||
519 | default: | ||
520 | mii_info->speed = SPEED_10; | ||
521 | break; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static int cis820x_ack_interrupt(struct ugeth_mii_info *mii_info) | ||
529 | { | ||
530 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
531 | |||
532 | ucc_geth_phy_read(mii_info, MII_CIS8201_ISTAT); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int cis820x_config_intr(struct ugeth_mii_info *mii_info) | ||
538 | { | ||
539 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
540 | |||
541 | if (mii_info->interrupts == MII_INTERRUPT_ENABLED) | ||
542 | ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, MII_CIS8201_IMASK_MASK); | ||
543 | else | ||
544 | ucc_geth_phy_write(mii_info, MII_CIS8201_IMASK, 0); | ||
545 | |||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | #define DM9161_DELAY 10 | ||
550 | |||
551 | static int dm9161_read_status(struct ugeth_mii_info *mii_info) | ||
552 | { | ||
553 | u16 status; | ||
554 | int err; | ||
555 | |||
556 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
557 | |||
558 | /* Update the link, but return if there | ||
559 | * was an error */ | ||
560 | err = genmii_update_link(mii_info); | ||
561 | if (err) | ||
562 | return err; | ||
563 | |||
564 | /* If the link is up, read the speed and duplex */ | ||
565 | /* If we aren't autonegotiating, assume speeds | ||
566 | * are as set */ | ||
567 | if (mii_info->autoneg && mii_info->link) { | ||
568 | status = ucc_geth_phy_read(mii_info, MII_DM9161_SCSR); | ||
569 | if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_100H)) | ||
570 | mii_info->speed = SPEED_100; | ||
571 | else | ||
572 | mii_info->speed = SPEED_10; | ||
573 | |||
574 | if (status & (MII_DM9161_SCSR_100F | MII_DM9161_SCSR_10F)) | ||
575 | mii_info->duplex = DUPLEX_FULL; | ||
576 | else | ||
577 | mii_info->duplex = DUPLEX_HALF; | ||
578 | } | ||
579 | |||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int dm9161_config_aneg(struct ugeth_mii_info *mii_info) | ||
584 | { | ||
585 | struct dm9161_private *priv = mii_info->priv; | ||
586 | |||
587 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
588 | |||
589 | if (0 == priv->resetdone) | ||
590 | return -EAGAIN; | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static void dm9161_timer(unsigned long data) | ||
596 | { | ||
597 | struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; | ||
598 | struct dm9161_private *priv = mii_info->priv; | ||
599 | u16 status = ucc_geth_phy_read(mii_info, MII_BMSR); | ||
600 | |||
601 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
602 | |||
603 | if (status & BMSR_ANEGCOMPLETE) { | ||
604 | priv->resetdone = 1; | ||
605 | } else | ||
606 | mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); | ||
607 | } | ||
608 | |||
609 | static int dm9161_init(struct ugeth_mii_info *mii_info) | ||
610 | { | ||
611 | struct dm9161_private *priv; | ||
612 | |||
613 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
614 | |||
615 | /* Allocate the private data structure */ | ||
616 | priv = kmalloc(sizeof(struct dm9161_private), GFP_KERNEL); | ||
617 | |||
618 | if (NULL == priv) | ||
619 | return -ENOMEM; | ||
620 | |||
621 | mii_info->priv = priv; | ||
622 | |||
623 | /* Reset is not done yet */ | ||
624 | priv->resetdone = 0; | ||
625 | |||
626 | ucc_geth_phy_write(mii_info, MII_BMCR, | ||
627 | ucc_geth_phy_read(mii_info, MII_BMCR) | BMCR_RESET); | ||
628 | |||
629 | ucc_geth_phy_write(mii_info, MII_BMCR, | ||
630 | ucc_geth_phy_read(mii_info, MII_BMCR) & ~BMCR_ISOLATE); | ||
631 | |||
632 | config_genmii_advert(mii_info); | ||
633 | /* Start/Restart aneg */ | ||
634 | genmii_config_aneg(mii_info); | ||
635 | |||
636 | /* Start a timer for DM9161_DELAY seconds to wait | ||
637 | * for the PHY to be ready */ | ||
638 | init_timer(&priv->timer); | ||
639 | priv->timer.function = &dm9161_timer; | ||
640 | priv->timer.data = (unsigned long)mii_info; | ||
641 | mod_timer(&priv->timer, jiffies + DM9161_DELAY * HZ); | ||
642 | |||
643 | return 0; | ||
644 | } | ||
645 | |||
646 | static void dm9161_close(struct ugeth_mii_info *mii_info) | ||
647 | { | ||
648 | struct dm9161_private *priv = mii_info->priv; | ||
649 | |||
650 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
651 | |||
652 | del_timer_sync(&priv->timer); | ||
653 | kfree(priv); | ||
654 | } | ||
655 | |||
656 | static int dm9161_ack_interrupt(struct ugeth_mii_info *mii_info) | ||
657 | { | ||
658 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
659 | |||
660 | /* Clear the interrupts by reading the reg */ | ||
661 | ucc_geth_phy_read(mii_info, MII_DM9161_INTR); | ||
662 | |||
663 | |||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int dm9161_config_intr(struct ugeth_mii_info *mii_info) | ||
668 | { | ||
669 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
670 | |||
671 | if (mii_info->interrupts == MII_INTERRUPT_ENABLED) | ||
672 | ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_INIT); | ||
673 | else | ||
674 | ucc_geth_phy_write(mii_info, MII_DM9161_INTR, MII_DM9161_INTR_STOP); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | /* Cicada 820x */ | ||
680 | static struct phy_info phy_info_cis820x = { | ||
681 | .phy_id = 0x000fc440, | ||
682 | .name = "Cicada Cis8204", | ||
683 | .phy_id_mask = 0x000fffc0, | ||
684 | .features = MII_GBIT_FEATURES, | ||
685 | .init = &cis820x_init, | ||
686 | .config_aneg = &gbit_config_aneg, | ||
687 | .read_status = &cis820x_read_status, | ||
688 | .ack_interrupt = &cis820x_ack_interrupt, | ||
689 | .config_intr = &cis820x_config_intr, | ||
690 | }; | ||
691 | |||
692 | static struct phy_info phy_info_dm9161 = { | ||
693 | .phy_id = 0x0181b880, | ||
694 | .phy_id_mask = 0x0ffffff0, | ||
695 | .name = "Davicom DM9161E", | ||
696 | .init = dm9161_init, | ||
697 | .config_aneg = dm9161_config_aneg, | ||
698 | .read_status = dm9161_read_status, | ||
699 | .close = dm9161_close, | ||
700 | }; | ||
701 | |||
702 | static struct phy_info phy_info_dm9161a = { | ||
703 | .phy_id = 0x0181b8a0, | ||
704 | .phy_id_mask = 0x0ffffff0, | ||
705 | .name = "Davicom DM9161A", | ||
706 | .features = MII_BASIC_FEATURES, | ||
707 | .init = dm9161_init, | ||
708 | .config_aneg = dm9161_config_aneg, | ||
709 | .read_status = dm9161_read_status, | ||
710 | .ack_interrupt = dm9161_ack_interrupt, | ||
711 | .config_intr = dm9161_config_intr, | ||
712 | .close = dm9161_close, | ||
713 | }; | ||
714 | |||
715 | static struct phy_info phy_info_marvell = { | ||
716 | .phy_id = 0x01410c00, | ||
717 | .phy_id_mask = 0xffffff00, | ||
718 | .name = "Marvell 88E11x1", | ||
719 | .features = MII_GBIT_FEATURES, | ||
720 | .init = &marvell_init, | ||
721 | .config_aneg = &marvell_config_aneg, | ||
722 | .read_status = &marvell_read_status, | ||
723 | .ack_interrupt = &marvell_ack_interrupt, | ||
724 | .config_intr = &marvell_config_intr, | ||
725 | }; | ||
726 | |||
727 | static struct phy_info phy_info_genmii = { | ||
728 | .phy_id = 0x00000000, | ||
729 | .phy_id_mask = 0x00000000, | ||
730 | .name = "Generic MII", | ||
731 | .features = MII_BASIC_FEATURES, | ||
732 | .config_aneg = genmii_config_aneg, | ||
733 | .read_status = genmii_read_status, | ||
734 | }; | ||
735 | |||
736 | static struct phy_info *phy_info[] = { | ||
737 | &phy_info_cis820x, | ||
738 | &phy_info_marvell, | ||
739 | &phy_info_dm9161, | ||
740 | &phy_info_dm9161a, | ||
741 | &phy_info_genmii, | ||
742 | NULL | ||
743 | }; | ||
744 | |||
745 | /* Use the PHY ID registers to determine what type of PHY is attached | ||
746 | * to device dev. return a struct phy_info structure describing that PHY | ||
747 | */ | ||
748 | struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info) | ||
749 | { | ||
750 | u16 phy_reg; | ||
751 | u32 phy_ID; | ||
752 | int i; | ||
753 | struct phy_info *theInfo = NULL; | ||
754 | struct net_device *dev = mii_info->dev; | ||
755 | |||
756 | ugphy_vdbg("%s: IN", __FUNCTION__); | ||
757 | |||
758 | /* Grab the bits from PHYIR1, and put them in the upper half */ | ||
759 | phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID1); | ||
760 | phy_ID = (phy_reg & 0xffff) << 16; | ||
761 | |||
762 | /* Grab the bits from PHYIR2, and put them in the lower half */ | ||
763 | phy_reg = ucc_geth_phy_read(mii_info, MII_PHYSID2); | ||
764 | phy_ID |= (phy_reg & 0xffff); | ||
765 | |||
766 | /* loop through all the known PHY types, and find one that */ | ||
767 | /* matches the ID we read from the PHY. */ | ||
768 | for (i = 0; phy_info[i]; i++) | ||
769 | if (phy_info[i]->phy_id == (phy_ID & phy_info[i]->phy_id_mask)){ | ||
770 | theInfo = phy_info[i]; | ||
771 | break; | ||
772 | } | ||
773 | |||
774 | /* This shouldn't happen, as we have generic PHY support */ | ||
775 | if (theInfo == NULL) { | ||
776 | ugphy_info("%s: PHY id %x is not supported!", dev->name, | ||
777 | phy_ID); | ||
778 | return NULL; | ||
779 | } else { | ||
780 | ugphy_info("%s: PHY is %s (%x)", dev->name, theInfo->name, | ||
781 | phy_ID); | ||
782 | } | ||
783 | |||
784 | return theInfo; | ||
785 | } | ||
diff --git a/drivers/net/ucc_geth_phy.h b/drivers/net/ucc_geth_phy.h deleted file mode 100644 index f5740783670f..000000000000 --- a/drivers/net/ucc_geth_phy.h +++ /dev/null | |||
@@ -1,217 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) Freescale Semicondutor, Inc. 2006. All rights reserved. | ||
3 | * | ||
4 | * Author: Shlomi Gridish <gridish@freescale.com> | ||
5 | * | ||
6 | * Description: | ||
7 | * UCC GETH Driver -- PHY handling | ||
8 | * | ||
9 | * Changelog: | ||
10 | * Jun 28, 2006 Li Yang <LeoLi@freescale.com> | ||
11 | * - Rearrange code and style fixes | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify it | ||
14 | * under the terms of the GNU General Public License as published by the | ||
15 | * Free Software Foundation; either version 2 of the License, or (at your | ||
16 | * option) any later version. | ||
17 | * | ||
18 | */ | ||
19 | #ifndef __UCC_GETH_PHY_H__ | ||
20 | #define __UCC_GETH_PHY_H__ | ||
21 | |||
22 | #define MII_end ((u32)-2) | ||
23 | #define MII_read ((u32)-1) | ||
24 | |||
25 | #define MIIMIND_BUSY 0x00000001 | ||
26 | #define MIIMIND_NOTVALID 0x00000004 | ||
27 | |||
28 | #define UGETH_AN_TIMEOUT 2000 | ||
29 | |||
30 | /* 1000BT control (Marvell & BCM54xx at least) */ | ||
31 | #define MII_1000BASETCONTROL 0x09 | ||
32 | #define MII_1000BASETCONTROL_FULLDUPLEXCAP 0x0200 | ||
33 | #define MII_1000BASETCONTROL_HALFDUPLEXCAP 0x0100 | ||
34 | |||
35 | /* Cicada Extended Control Register 1 */ | ||
36 | #define MII_CIS8201_EXT_CON1 0x17 | ||
37 | #define MII_CIS8201_EXTCON1_INIT 0x0000 | ||
38 | |||
39 | /* Cicada Interrupt Mask Register */ | ||
40 | #define MII_CIS8201_IMASK 0x19 | ||
41 | #define MII_CIS8201_IMASK_IEN 0x8000 | ||
42 | #define MII_CIS8201_IMASK_SPEED 0x4000 | ||
43 | #define MII_CIS8201_IMASK_LINK 0x2000 | ||
44 | #define MII_CIS8201_IMASK_DUPLEX 0x1000 | ||
45 | #define MII_CIS8201_IMASK_MASK 0xf000 | ||
46 | |||
47 | /* Cicada Interrupt Status Register */ | ||
48 | #define MII_CIS8201_ISTAT 0x1a | ||
49 | #define MII_CIS8201_ISTAT_STATUS 0x8000 | ||
50 | #define MII_CIS8201_ISTAT_SPEED 0x4000 | ||
51 | #define MII_CIS8201_ISTAT_LINK 0x2000 | ||
52 | #define MII_CIS8201_ISTAT_DUPLEX 0x1000 | ||
53 | |||
54 | /* Cicada Auxiliary Control/Status Register */ | ||
55 | #define MII_CIS8201_AUX_CONSTAT 0x1c | ||
56 | #define MII_CIS8201_AUXCONSTAT_INIT 0x0004 | ||
57 | #define MII_CIS8201_AUXCONSTAT_DUPLEX 0x0020 | ||
58 | #define MII_CIS8201_AUXCONSTAT_SPEED 0x0018 | ||
59 | #define MII_CIS8201_AUXCONSTAT_GBIT 0x0010 | ||
60 | #define MII_CIS8201_AUXCONSTAT_100 0x0008 | ||
61 | |||
62 | /* 88E1011 PHY Status Register */ | ||
63 | #define MII_M1011_PHY_SPEC_STATUS 0x11 | ||
64 | #define MII_M1011_PHY_SPEC_STATUS_1000 0x8000 | ||
65 | #define MII_M1011_PHY_SPEC_STATUS_100 0x4000 | ||
66 | #define MII_M1011_PHY_SPEC_STATUS_SPD_MASK 0xc000 | ||
67 | #define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX 0x2000 | ||
68 | #define MII_M1011_PHY_SPEC_STATUS_RESOLVED 0x0800 | ||
69 | #define MII_M1011_PHY_SPEC_STATUS_LINK 0x0400 | ||
70 | |||
71 | #define MII_M1011_IEVENT 0x13 | ||
72 | #define MII_M1011_IEVENT_CLEAR 0x0000 | ||
73 | |||
74 | #define MII_M1011_IMASK 0x12 | ||
75 | #define MII_M1011_IMASK_INIT 0x6400 | ||
76 | #define MII_M1011_IMASK_CLEAR 0x0000 | ||
77 | |||
78 | #define MII_DM9161_SCR 0x10 | ||
79 | #define MII_DM9161_SCR_INIT 0x0610 | ||
80 | |||
81 | /* DM9161 Specified Configuration and Status Register */ | ||
82 | #define MII_DM9161_SCSR 0x11 | ||
83 | #define MII_DM9161_SCSR_100F 0x8000 | ||
84 | #define MII_DM9161_SCSR_100H 0x4000 | ||
85 | #define MII_DM9161_SCSR_10F 0x2000 | ||
86 | #define MII_DM9161_SCSR_10H 0x1000 | ||
87 | |||
88 | /* DM9161 Interrupt Register */ | ||
89 | #define MII_DM9161_INTR 0x15 | ||
90 | #define MII_DM9161_INTR_PEND 0x8000 | ||
91 | #define MII_DM9161_INTR_DPLX_MASK 0x0800 | ||
92 | #define MII_DM9161_INTR_SPD_MASK 0x0400 | ||
93 | #define MII_DM9161_INTR_LINK_MASK 0x0200 | ||
94 | #define MII_DM9161_INTR_MASK 0x0100 | ||
95 | #define MII_DM9161_INTR_DPLX_CHANGE 0x0010 | ||
96 | #define MII_DM9161_INTR_SPD_CHANGE 0x0008 | ||
97 | #define MII_DM9161_INTR_LINK_CHANGE 0x0004 | ||
98 | #define MII_DM9161_INTR_INIT 0x0000 | ||
99 | #define MII_DM9161_INTR_STOP \ | ||
100 | (MII_DM9161_INTR_DPLX_MASK | MII_DM9161_INTR_SPD_MASK \ | ||
101 | | MII_DM9161_INTR_LINK_MASK | MII_DM9161_INTR_MASK) | ||
102 | |||
103 | /* DM9161 10BT Configuration/Status */ | ||
104 | #define MII_DM9161_10BTCSR 0x12 | ||
105 | #define MII_DM9161_10BTCSR_INIT 0x7800 | ||
106 | |||
107 | #define MII_BASIC_FEATURES (SUPPORTED_10baseT_Half | \ | ||
108 | SUPPORTED_10baseT_Full | \ | ||
109 | SUPPORTED_100baseT_Half | \ | ||
110 | SUPPORTED_100baseT_Full | \ | ||
111 | SUPPORTED_Autoneg | \ | ||
112 | SUPPORTED_TP | \ | ||
113 | SUPPORTED_MII) | ||
114 | |||
115 | #define MII_GBIT_FEATURES (MII_BASIC_FEATURES | \ | ||
116 | SUPPORTED_1000baseT_Half | \ | ||
117 | SUPPORTED_1000baseT_Full) | ||
118 | |||
119 | #define MII_READ_COMMAND 0x00000001 | ||
120 | |||
121 | #define MII_INTERRUPT_DISABLED 0x0 | ||
122 | #define MII_INTERRUPT_ENABLED 0x1 | ||
123 | /* Taken from mii_if_info and sungem_phy.h */ | ||
124 | struct ugeth_mii_info { | ||
125 | /* Information about the PHY type */ | ||
126 | /* And management functions */ | ||
127 | struct phy_info *phyinfo; | ||
128 | |||
129 | struct ucc_mii_mng *mii_regs; | ||
130 | |||
131 | /* forced speed & duplex (no autoneg) | ||
132 | * partner speed & duplex & pause (autoneg) | ||
133 | */ | ||
134 | int speed; | ||
135 | int duplex; | ||
136 | int pause; | ||
137 | |||
138 | /* The most recently read link state */ | ||
139 | int link; | ||
140 | |||
141 | /* Enabled Interrupts */ | ||
142 | u32 interrupts; | ||
143 | |||
144 | u32 advertising; | ||
145 | int autoneg; | ||
146 | int mii_id; | ||
147 | |||
148 | /* private data pointer */ | ||
149 | /* For use by PHYs to maintain extra state */ | ||
150 | void *priv; | ||
151 | |||
152 | /* Provided by host chip */ | ||
153 | struct net_device *dev; | ||
154 | |||
155 | /* A lock to ensure that only one thing can read/write | ||
156 | * the MDIO bus at a time */ | ||
157 | spinlock_t mdio_lock; | ||
158 | |||
159 | /* Provided by ethernet driver */ | ||
160 | int (*mdio_read) (struct net_device * dev, int mii_id, int reg); | ||
161 | void (*mdio_write) (struct net_device * dev, int mii_id, int reg, | ||
162 | int val); | ||
163 | }; | ||
164 | |||
165 | /* struct phy_info: a structure which defines attributes for a PHY | ||
166 | * | ||
167 | * id will contain a number which represents the PHY. During | ||
168 | * startup, the driver will poll the PHY to find out what its | ||
169 | * UID--as defined by registers 2 and 3--is. The 32-bit result | ||
170 | * gotten from the PHY will be ANDed with phy_id_mask to | ||
171 | * discard any bits which may change based on revision numbers | ||
172 | * unimportant to functionality | ||
173 | * | ||
174 | * There are 6 commands which take a ugeth_mii_info structure. | ||
175 | * Each PHY must declare config_aneg, and read_status. | ||
176 | */ | ||
177 | struct phy_info { | ||
178 | u32 phy_id; | ||
179 | char *name; | ||
180 | unsigned int phy_id_mask; | ||
181 | u32 features; | ||
182 | |||
183 | /* Called to initialize the PHY */ | ||
184 | int (*init) (struct ugeth_mii_info * mii_info); | ||
185 | |||
186 | /* Called to suspend the PHY for power */ | ||
187 | int (*suspend) (struct ugeth_mii_info * mii_info); | ||
188 | |||
189 | /* Reconfigures autonegotiation (or disables it) */ | ||
190 | int (*config_aneg) (struct ugeth_mii_info * mii_info); | ||
191 | |||
192 | /* Determines the negotiated speed and duplex */ | ||
193 | int (*read_status) (struct ugeth_mii_info * mii_info); | ||
194 | |||
195 | /* Clears any pending interrupts */ | ||
196 | int (*ack_interrupt) (struct ugeth_mii_info * mii_info); | ||
197 | |||
198 | /* Enables or disables interrupts */ | ||
199 | int (*config_intr) (struct ugeth_mii_info * mii_info); | ||
200 | |||
201 | /* Clears up any memory if needed */ | ||
202 | void (*close) (struct ugeth_mii_info * mii_info); | ||
203 | }; | ||
204 | |||
205 | struct phy_info *get_phy_info(struct ugeth_mii_info *mii_info); | ||
206 | void write_phy_reg(struct net_device *dev, int mii_id, int regnum, int value); | ||
207 | int read_phy_reg(struct net_device *dev, int mii_id, int regnum); | ||
208 | void mii_clear_phy_interrupt(struct ugeth_mii_info *mii_info); | ||
209 | void mii_configure_phy_interrupt(struct ugeth_mii_info *mii_info, | ||
210 | u32 interrupts); | ||
211 | |||
212 | struct dm9161_private { | ||
213 | struct timer_list timer; | ||
214 | int resetdone; | ||
215 | }; | ||
216 | |||
217 | #endif /* __UCC_GETH_PHY_H__ */ | ||
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c index 00e0aaadabcc..9ec6cf2e510e 100644 --- a/drivers/net/wan/hdlc_cisco.c +++ b/drivers/net/wan/hdlc_cisco.c | |||
@@ -37,16 +37,16 @@ | |||
37 | struct hdlc_header { | 37 | struct hdlc_header { |
38 | u8 address; | 38 | u8 address; |
39 | u8 control; | 39 | u8 control; |
40 | u16 protocol; | 40 | __be16 protocol; |
41 | }__attribute__ ((packed)); | 41 | }__attribute__ ((packed)); |
42 | 42 | ||
43 | 43 | ||
44 | struct cisco_packet { | 44 | struct cisco_packet { |
45 | u32 type; /* code */ | 45 | __be32 type; /* code */ |
46 | u32 par1; | 46 | __be32 par1; |
47 | u32 par2; | 47 | __be32 par2; |
48 | u16 rel; /* reliability */ | 48 | __be16 rel; /* reliability */ |
49 | u32 time; | 49 | __be32 time; |
50 | }__attribute__ ((packed)); | 50 | }__attribute__ ((packed)); |
51 | #define CISCO_PACKET_LEN 18 | 51 | #define CISCO_PACKET_LEN 18 |
52 | #define CISCO_BIG_PACKET_LEN 20 | 52 | #define CISCO_BIG_PACKET_LEN 20 |
@@ -97,7 +97,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev, | |||
97 | 97 | ||
98 | 98 | ||
99 | static void cisco_keepalive_send(struct net_device *dev, u32 type, | 99 | static void cisco_keepalive_send(struct net_device *dev, u32 type, |
100 | u32 par1, u32 par2) | 100 | __be32 par1, __be32 par2) |
101 | { | 101 | { |
102 | struct sk_buff *skb; | 102 | struct sk_buff *skb; |
103 | struct cisco_packet *data; | 103 | struct cisco_packet *data; |
@@ -115,9 +115,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type, | |||
115 | data = (struct cisco_packet*)(skb->data + 4); | 115 | data = (struct cisco_packet*)(skb->data + 4); |
116 | 116 | ||
117 | data->type = htonl(type); | 117 | data->type = htonl(type); |
118 | data->par1 = htonl(par1); | 118 | data->par1 = par1; |
119 | data->par2 = htonl(par2); | 119 | data->par2 = par2; |
120 | data->rel = 0xFFFF; | 120 | data->rel = __constant_htons(0xFFFF); |
121 | /* we will need do_div here if 1000 % HZ != 0 */ | 121 | /* we will need do_div here if 1000 % HZ != 0 */ |
122 | data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ)); | 122 | data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ)); |
123 | 123 | ||
@@ -193,7 +193,7 @@ static int cisco_rx(struct sk_buff *skb) | |||
193 | case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ | 193 | case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */ |
194 | in_dev = dev->ip_ptr; | 194 | in_dev = dev->ip_ptr; |
195 | addr = 0; | 195 | addr = 0; |
196 | mask = ~0; /* is the mask correct? */ | 196 | mask = __constant_htonl(~0); /* is the mask correct? */ |
197 | 197 | ||
198 | if (in_dev != NULL) { | 198 | if (in_dev != NULL) { |
199 | struct in_ifaddr **ifap = &in_dev->ifa_list; | 199 | struct in_ifaddr **ifap = &in_dev->ifa_list; |
@@ -245,7 +245,7 @@ static int cisco_rx(struct sk_buff *skb) | |||
245 | } /* switch(protocol) */ | 245 | } /* switch(protocol) */ |
246 | 246 | ||
247 | printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name, | 247 | printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name, |
248 | data->protocol); | 248 | ntohs(data->protocol)); |
249 | dev_kfree_skb_any(skb); | 249 | dev_kfree_skb_any(skb); |
250 | return NET_RX_DROP; | 250 | return NET_RX_DROP; |
251 | 251 | ||
@@ -270,8 +270,9 @@ static void cisco_timer(unsigned long arg) | |||
270 | netif_dormant_on(dev); | 270 | netif_dormant_on(dev); |
271 | } | 271 | } |
272 | 272 | ||
273 | cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq, | 273 | cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, |
274 | state(hdlc)->rxseq); | 274 | htonl(++state(hdlc)->txseq), |
275 | htonl(state(hdlc)->rxseq)); | ||
275 | state(hdlc)->request_sent = 1; | 276 | state(hdlc)->request_sent = 1; |
276 | state(hdlc)->timer.expires = jiffies + | 277 | state(hdlc)->timer.expires = jiffies + |
277 | state(hdlc)->settings.interval * HZ; | 278 | state(hdlc)->settings.interval * HZ; |
diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index aeb2789adf26..15b6e07a4382 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c | |||
@@ -288,31 +288,31 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) | |||
288 | struct sk_buff *skb = *skb_p; | 288 | struct sk_buff *skb = *skb_p; |
289 | 289 | ||
290 | switch (skb->protocol) { | 290 | switch (skb->protocol) { |
291 | case __constant_ntohs(NLPID_CCITT_ANSI_LMI): | 291 | case __constant_htons(NLPID_CCITT_ANSI_LMI): |
292 | head_len = 4; | 292 | head_len = 4; |
293 | skb_push(skb, head_len); | 293 | skb_push(skb, head_len); |
294 | skb->data[3] = NLPID_CCITT_ANSI_LMI; | 294 | skb->data[3] = NLPID_CCITT_ANSI_LMI; |
295 | break; | 295 | break; |
296 | 296 | ||
297 | case __constant_ntohs(NLPID_CISCO_LMI): | 297 | case __constant_htons(NLPID_CISCO_LMI): |
298 | head_len = 4; | 298 | head_len = 4; |
299 | skb_push(skb, head_len); | 299 | skb_push(skb, head_len); |
300 | skb->data[3] = NLPID_CISCO_LMI; | 300 | skb->data[3] = NLPID_CISCO_LMI; |
301 | break; | 301 | break; |
302 | 302 | ||
303 | case __constant_ntohs(ETH_P_IP): | 303 | case __constant_htons(ETH_P_IP): |
304 | head_len = 4; | 304 | head_len = 4; |
305 | skb_push(skb, head_len); | 305 | skb_push(skb, head_len); |
306 | skb->data[3] = NLPID_IP; | 306 | skb->data[3] = NLPID_IP; |
307 | break; | 307 | break; |
308 | 308 | ||
309 | case __constant_ntohs(ETH_P_IPV6): | 309 | case __constant_htons(ETH_P_IPV6): |
310 | head_len = 4; | 310 | head_len = 4; |
311 | skb_push(skb, head_len); | 311 | skb_push(skb, head_len); |
312 | skb->data[3] = NLPID_IPV6; | 312 | skb->data[3] = NLPID_IPV6; |
313 | break; | 313 | break; |
314 | 314 | ||
315 | case __constant_ntohs(ETH_P_802_3): | 315 | case __constant_htons(ETH_P_802_3): |
316 | head_len = 10; | 316 | head_len = 10; |
317 | if (skb_headroom(skb) < head_len) { | 317 | if (skb_headroom(skb) < head_len) { |
318 | struct sk_buff *skb2 = skb_realloc_headroom(skb, | 318 | struct sk_buff *skb2 = skb_realloc_headroom(skb, |
@@ -340,7 +340,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) | |||
340 | skb->data[5] = FR_PAD; | 340 | skb->data[5] = FR_PAD; |
341 | skb->data[6] = FR_PAD; | 341 | skb->data[6] = FR_PAD; |
342 | skb->data[7] = FR_PAD; | 342 | skb->data[7] = FR_PAD; |
343 | *(u16*)(skb->data + 8) = skb->protocol; | 343 | *(__be16*)(skb->data + 8) = skb->protocol; |
344 | } | 344 | } |
345 | 345 | ||
346 | dlci_to_q922(skb->data, dlci); | 346 | dlci_to_q922(skb->data, dlci); |
@@ -974,8 +974,8 @@ static int fr_rx(struct sk_buff *skb) | |||
974 | 974 | ||
975 | } else if (skb->len > 10 && data[3] == FR_PAD && | 975 | } else if (skb->len > 10 && data[3] == FR_PAD && |
976 | data[4] == NLPID_SNAP && data[5] == FR_PAD) { | 976 | data[4] == NLPID_SNAP && data[5] == FR_PAD) { |
977 | u16 oui = ntohs(*(u16*)(data + 6)); | 977 | u16 oui = ntohs(*(__be16*)(data + 6)); |
978 | u16 pid = ntohs(*(u16*)(data + 8)); | 978 | u16 pid = ntohs(*(__be16*)(data + 8)); |
979 | skb_pull(skb, 10); | 979 | skb_pull(skb, 10); |
980 | 980 | ||
981 | switch ((((u32)oui) << 16) | pid) { | 981 | switch ((((u32)oui) << 16) | pid) { |
@@ -1127,7 +1127,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) | |||
1127 | memcpy(dev->dev_addr, "\x00\x01", 2); | 1127 | memcpy(dev->dev_addr, "\x00\x01", 2); |
1128 | get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); | 1128 | get_random_bytes(dev->dev_addr + 2, ETH_ALEN - 2); |
1129 | } else { | 1129 | } else { |
1130 | *(u16*)dev->dev_addr = htons(dlci); | 1130 | *(__be16*)dev->dev_addr = htons(dlci); |
1131 | dlci_to_q922(dev->broadcast, dlci); | 1131 | dlci_to_q922(dev->broadcast, dlci); |
1132 | } | 1132 | } |
1133 | dev->hard_start_xmit = pvc_xmit; | 1133 | dev->hard_start_xmit = pvc_xmit; |
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 4426841b2be6..c4b3dc291a5a 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig | |||
@@ -265,6 +265,19 @@ config IPW2200_DEBUG | |||
265 | 265 | ||
266 | If you are not sure, say N here. | 266 | If you are not sure, say N here. |
267 | 267 | ||
268 | config LIBERTAS_USB | ||
269 | tristate "Marvell Libertas 8388 802.11a/b/g cards" | ||
270 | depends on NET_RADIO && USB | ||
271 | select FW_LOADER | ||
272 | ---help--- | ||
273 | A driver for Marvell Libertas 8388 USB devices. | ||
274 | |||
275 | config LIBERTAS_USB_DEBUG | ||
276 | bool "Enable full debugging output in the Libertas USB module." | ||
277 | depends on LIBERTAS_USB | ||
278 | ---help--- | ||
279 | Debugging support. | ||
280 | |||
268 | config AIRO | 281 | config AIRO |
269 | tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" | 282 | tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" |
270 | depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) | 283 | depends on ISA_DMA_API && WLAN_80211 && (PCI || BROKEN) |
diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index c613af17a159..d2124602263b 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile | |||
@@ -43,3 +43,4 @@ obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o | |||
43 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o | 43 | obj-$(CONFIG_PCMCIA_WL3501) += wl3501_cs.o |
44 | 44 | ||
45 | obj-$(CONFIG_USB_ZD1201) += zd1201.o | 45 | obj-$(CONFIG_USB_ZD1201) += zd1201.o |
46 | obj-$(CONFIG_LIBERTAS_USB) += libertas/ | ||
diff --git a/drivers/net/wireless/README b/drivers/net/wireless/README deleted file mode 100644 index 0c274bf6d45e..000000000000 --- a/drivers/net/wireless/README +++ /dev/null | |||
@@ -1,25 +0,0 @@ | |||
1 | README | ||
2 | ------ | ||
3 | |||
4 | This directory is mostly for Wireless LAN drivers, in their | ||
5 | various incarnations (ISA, PCI, Pcmcia...). | ||
6 | This separate directory is needed because a lot of driver work | ||
7 | on different bus (typically PCI + Pcmcia) and share 95% of the | ||
8 | code. This allow the code and the config options to be in one single | ||
9 | place instead of scattered all over the driver tree, which is never | ||
10 | 100% satisfactory. | ||
11 | |||
12 | Note : if you want more info on the topic of Wireless LANs, | ||
13 | you are kindly invited to have a look at the Wireless Howto : | ||
14 | http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/ | ||
15 | Some Wireless LAN drivers, like orinoco_cs, require the use of | ||
16 | Wireless Tools to be configured : | ||
17 | http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html | ||
18 | |||
19 | Special notes for distribution maintainers : | ||
20 | 1) wvlan_cs will be discontinued soon in favor of orinoco_cs | ||
21 | 2) Please add Wireless Tools support in your scripts | ||
22 | |||
23 | Have fun... | ||
24 | |||
25 | Jean | ||
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 7fe0a61091a6..f21bbafcb728 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
@@ -1145,6 +1145,7 @@ static void airo_networks_free(struct airo_info *ai); | |||
1145 | struct airo_info { | 1145 | struct airo_info { |
1146 | struct net_device_stats stats; | 1146 | struct net_device_stats stats; |
1147 | struct net_device *dev; | 1147 | struct net_device *dev; |
1148 | struct list_head dev_list; | ||
1148 | /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we | 1149 | /* Note, we can have MAX_FIDS outstanding. FIDs are 16-bits, so we |
1149 | use the high bit to mark whether it is in use. */ | 1150 | use the high bit to mark whether it is in use. */ |
1150 | #define MAX_FIDS 6 | 1151 | #define MAX_FIDS 6 |
@@ -2360,6 +2361,21 @@ static int airo_change_mtu(struct net_device *dev, int new_mtu) | |||
2360 | return 0; | 2361 | return 0; |
2361 | } | 2362 | } |
2362 | 2363 | ||
2364 | static LIST_HEAD(airo_devices); | ||
2365 | |||
2366 | static void add_airo_dev(struct airo_info *ai) | ||
2367 | { | ||
2368 | /* Upper layers already keep track of PCI devices, | ||
2369 | * so we only need to remember our non-PCI cards. */ | ||
2370 | if (!ai->pci) | ||
2371 | list_add_tail(&ai->dev_list, &airo_devices); | ||
2372 | } | ||
2373 | |||
2374 | static void del_airo_dev(struct airo_info *ai) | ||
2375 | { | ||
2376 | if (!ai->pci) | ||
2377 | list_del(&ai->dev_list); | ||
2378 | } | ||
2363 | 2379 | ||
2364 | static int airo_close(struct net_device *dev) { | 2380 | static int airo_close(struct net_device *dev) { |
2365 | struct airo_info *ai = dev->priv; | 2381 | struct airo_info *ai = dev->priv; |
@@ -2381,8 +2397,6 @@ static int airo_close(struct net_device *dev) { | |||
2381 | return 0; | 2397 | return 0; |
2382 | } | 2398 | } |
2383 | 2399 | ||
2384 | static void del_airo_dev( struct net_device *dev ); | ||
2385 | |||
2386 | void stop_airo_card( struct net_device *dev, int freeres ) | 2400 | void stop_airo_card( struct net_device *dev, int freeres ) |
2387 | { | 2401 | { |
2388 | struct airo_info *ai = dev->priv; | 2402 | struct airo_info *ai = dev->priv; |
@@ -2434,14 +2448,12 @@ void stop_airo_card( struct net_device *dev, int freeres ) | |||
2434 | } | 2448 | } |
2435 | } | 2449 | } |
2436 | crypto_free_cipher(ai->tfm); | 2450 | crypto_free_cipher(ai->tfm); |
2437 | del_airo_dev( dev ); | 2451 | del_airo_dev(ai); |
2438 | free_netdev( dev ); | 2452 | free_netdev( dev ); |
2439 | } | 2453 | } |
2440 | 2454 | ||
2441 | EXPORT_SYMBOL(stop_airo_card); | 2455 | EXPORT_SYMBOL(stop_airo_card); |
2442 | 2456 | ||
2443 | static int add_airo_dev( struct net_device *dev ); | ||
2444 | |||
2445 | static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) | 2457 | static int wll_header_parse(struct sk_buff *skb, unsigned char *haddr) |
2446 | { | 2458 | { |
2447 | memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); | 2459 | memcpy(haddr, skb_mac_header(skb) + 10, ETH_ALEN); |
@@ -2740,8 +2752,6 @@ static int airo_networks_allocate(struct airo_info *ai) | |||
2740 | 2752 | ||
2741 | static void airo_networks_free(struct airo_info *ai) | 2753 | static void airo_networks_free(struct airo_info *ai) |
2742 | { | 2754 | { |
2743 | if (!ai->networks) | ||
2744 | return; | ||
2745 | kfree(ai->networks); | 2755 | kfree(ai->networks); |
2746 | ai->networks = NULL; | 2756 | ai->networks = NULL; |
2747 | } | 2757 | } |
@@ -2816,12 +2826,10 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, | |||
2816 | if (IS_ERR(ai->airo_thread_task)) | 2826 | if (IS_ERR(ai->airo_thread_task)) |
2817 | goto err_out_free; | 2827 | goto err_out_free; |
2818 | ai->tfm = NULL; | 2828 | ai->tfm = NULL; |
2819 | rc = add_airo_dev( dev ); | 2829 | add_airo_dev(ai); |
2820 | if (rc) | ||
2821 | goto err_out_thr; | ||
2822 | 2830 | ||
2823 | if (airo_networks_allocate (ai)) | 2831 | if (airo_networks_allocate (ai)) |
2824 | goto err_out_unlink; | 2832 | goto err_out_thr; |
2825 | airo_networks_initialize (ai); | 2833 | airo_networks_initialize (ai); |
2826 | 2834 | ||
2827 | /* The Airo-specific entries in the device structure. */ | 2835 | /* The Airo-specific entries in the device structure. */ |
@@ -2937,9 +2945,8 @@ err_out_irq: | |||
2937 | free_irq(dev->irq, dev); | 2945 | free_irq(dev->irq, dev); |
2938 | err_out_nets: | 2946 | err_out_nets: |
2939 | airo_networks_free(ai); | 2947 | airo_networks_free(ai); |
2940 | err_out_unlink: | ||
2941 | del_airo_dev(dev); | ||
2942 | err_out_thr: | 2948 | err_out_thr: |
2949 | del_airo_dev(ai); | ||
2943 | set_bit(JOB_DIE, &ai->jobs); | 2950 | set_bit(JOB_DIE, &ai->jobs); |
2944 | kthread_stop(ai->airo_thread_task); | 2951 | kthread_stop(ai->airo_thread_task); |
2945 | err_out_free: | 2952 | err_out_free: |
@@ -5535,11 +5542,6 @@ static int proc_close( struct inode *inode, struct file *file ) | |||
5535 | return 0; | 5542 | return 0; |
5536 | } | 5543 | } |
5537 | 5544 | ||
5538 | static struct net_device_list { | ||
5539 | struct net_device *dev; | ||
5540 | struct net_device_list *next; | ||
5541 | } *airo_devices; | ||
5542 | |||
5543 | /* Since the card doesn't automatically switch to the right WEP mode, | 5545 | /* Since the card doesn't automatically switch to the right WEP mode, |
5544 | we will make it do it. If the card isn't associated, every secs we | 5546 | we will make it do it. If the card isn't associated, every secs we |
5545 | will switch WEP modes to see if that will help. If the card is | 5547 | will switch WEP modes to see if that will help. If the card is |
@@ -5582,26 +5584,6 @@ static void timer_func( struct net_device *dev ) { | |||
5582 | apriv->expires = RUN_AT(HZ*3); | 5584 | apriv->expires = RUN_AT(HZ*3); |
5583 | } | 5585 | } |
5584 | 5586 | ||
5585 | static int add_airo_dev( struct net_device *dev ) { | ||
5586 | struct net_device_list *node = kmalloc( sizeof( *node ), GFP_KERNEL ); | ||
5587 | if ( !node ) | ||
5588 | return -ENOMEM; | ||
5589 | |||
5590 | node->dev = dev; | ||
5591 | node->next = airo_devices; | ||
5592 | airo_devices = node; | ||
5593 | |||
5594 | return 0; | ||
5595 | } | ||
5596 | |||
5597 | static void del_airo_dev( struct net_device *dev ) { | ||
5598 | struct net_device_list **p = &airo_devices; | ||
5599 | while( *p && ( (*p)->dev != dev ) ) | ||
5600 | p = &(*p)->next; | ||
5601 | if ( *p && (*p)->dev == dev ) | ||
5602 | *p = (*p)->next; | ||
5603 | } | ||
5604 | |||
5605 | #ifdef CONFIG_PCI | 5587 | #ifdef CONFIG_PCI |
5606 | static int __devinit airo_pci_probe(struct pci_dev *pdev, | 5588 | static int __devinit airo_pci_probe(struct pci_dev *pdev, |
5607 | const struct pci_device_id *pent) | 5589 | const struct pci_device_id *pent) |
@@ -5625,6 +5607,10 @@ static int __devinit airo_pci_probe(struct pci_dev *pdev, | |||
5625 | 5607 | ||
5626 | static void __devexit airo_pci_remove(struct pci_dev *pdev) | 5608 | static void __devexit airo_pci_remove(struct pci_dev *pdev) |
5627 | { | 5609 | { |
5610 | struct net_device *dev = pci_get_drvdata(pdev); | ||
5611 | |||
5612 | airo_print_info(dev->name, "Unregistering..."); | ||
5613 | stop_airo_card(dev, 1); | ||
5628 | } | 5614 | } |
5629 | 5615 | ||
5630 | static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) | 5616 | static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) |
@@ -5750,9 +5736,11 @@ static int __init airo_init_module( void ) | |||
5750 | 5736 | ||
5751 | static void __exit airo_cleanup_module( void ) | 5737 | static void __exit airo_cleanup_module( void ) |
5752 | { | 5738 | { |
5753 | while( airo_devices ) { | 5739 | struct airo_info *ai; |
5754 | airo_print_info(airo_devices->dev->name, "Unregistering...\n"); | 5740 | while(!list_empty(&airo_devices)) { |
5755 | stop_airo_card( airo_devices->dev, 1 ); | 5741 | ai = list_entry(airo_devices.next, struct airo_info, dev_list); |
5742 | airo_print_info(ai->dev->name, "Unregistering..."); | ||
5743 | stop_airo_card(ai->dev, 1); | ||
5756 | } | 5744 | } |
5757 | #ifdef CONFIG_PCI | 5745 | #ifdef CONFIG_PCI |
5758 | pci_unregister_driver(&airo_driver); | 5746 | pci_unregister_driver(&airo_driver); |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx.h b/drivers/net/wireless/bcm43xx/bcm43xx.h index 95ff175d8f33..f8483c179e4c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx.h | |||
@@ -277,11 +277,14 @@ | |||
277 | #define BCM43xx_SBTMSTATELOW_REJECT 0x02 | 277 | #define BCM43xx_SBTMSTATELOW_REJECT 0x02 |
278 | #define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 | 278 | #define BCM43xx_SBTMSTATELOW_CLOCK 0x10000 |
279 | #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 | 279 | #define BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK 0x20000 |
280 | #define BCM43xx_SBTMSTATELOW_G_MODE_ENABLE 0x20000000 | ||
280 | 281 | ||
281 | /* sbtmstatehigh state flags */ | 282 | /* sbtmstatehigh state flags */ |
282 | #define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001 | 283 | #define BCM43xx_SBTMSTATEHIGH_SERROR 0x00000001 |
283 | #define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004 | 284 | #define BCM43xx_SBTMSTATEHIGH_BUSY 0x00000004 |
284 | #define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020 | 285 | #define BCM43xx_SBTMSTATEHIGH_TIMEOUT 0x00000020 |
286 | #define BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL 0x00010000 | ||
287 | #define BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL 0x00020000 | ||
285 | #define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000 | 288 | #define BCM43xx_SBTMSTATEHIGH_COREFLAGS 0x1FFF0000 |
286 | #define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000 | 289 | #define BCM43xx_SBTMSTATEHIGH_DMA64BIT 0x10000000 |
287 | #define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000 | 290 | #define BCM43xx_SBTMSTATEHIGH_GATEDCLK 0x20000000 |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c index c947025d655f..d2df6a0100a1 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_ethtool.c | |||
@@ -32,7 +32,7 @@ | |||
32 | #include <linux/netdevice.h> | 32 | #include <linux/netdevice.h> |
33 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
34 | #include <linux/string.h> | 34 | #include <linux/string.h> |
35 | #include <linux/utsrelease.h> | 35 | #include <linux/utsname.h> |
36 | 36 | ||
37 | 37 | ||
38 | static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) | 38 | static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) |
@@ -40,7 +40,7 @@ static void bcm43xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo * | |||
40 | struct bcm43xx_private *bcm = bcm43xx_priv(dev); | 40 | struct bcm43xx_private *bcm = bcm43xx_priv(dev); |
41 | 41 | ||
42 | strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); | 42 | strncpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); |
43 | strncpy(info->version, UTS_RELEASE, sizeof(info->version)); | 43 | strncpy(info->version, utsname()->release, sizeof(info->version)); |
44 | strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); | 44 | strncpy(info->bus_info, pci_name(bcm->pci_dev), ETHTOOL_BUSINFO_LEN); |
45 | } | 45 | } |
46 | 46 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_main.c b/drivers/net/wireless/bcm43xx/bcm43xx_main.c index a38e7eec0e62..5e96bca6730a 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_main.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_main.c | |||
@@ -1407,7 +1407,7 @@ void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy) | |||
1407 | & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); | 1407 | & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); |
1408 | } else { | 1408 | } else { |
1409 | if (connect_phy) | 1409 | if (connect_phy) |
1410 | flags |= 0x20000000; | 1410 | flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; |
1411 | bcm43xx_phy_connect(bcm, connect_phy); | 1411 | bcm43xx_phy_connect(bcm, connect_phy); |
1412 | bcm43xx_core_enable(bcm, flags); | 1412 | bcm43xx_core_enable(bcm, flags); |
1413 | bcm43xx_write16(bcm, 0x03E6, 0x0000); | 1413 | bcm43xx_write16(bcm, 0x03E6, 0x0000); |
@@ -3604,7 +3604,7 @@ int bcm43xx_select_wireless_core(struct bcm43xx_private *bcm, | |||
3604 | u32 sbtmstatelow; | 3604 | u32 sbtmstatelow; |
3605 | 3605 | ||
3606 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | 3606 | sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
3607 | sbtmstatelow |= 0x20000000; | 3607 | sbtmstatelow |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; |
3608 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); | 3608 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); |
3609 | } | 3609 | } |
3610 | err = wireless_core_up(bcm, 1); | 3610 | err = wireless_core_up(bcm, 1); |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c index 72529a440f15..b37f1e348700 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.c | |||
@@ -168,16 +168,16 @@ int bcm43xx_phy_connect(struct bcm43xx_private *bcm, int connect) | |||
168 | 168 | ||
169 | flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); | 169 | flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); |
170 | if (connect) { | 170 | if (connect) { |
171 | if (!(flags & 0x00010000)) | 171 | if (!(flags & BCM43xx_SBTMSTATEHIGH_G_PHY_AVAIL)) |
172 | return -ENODEV; | 172 | return -ENODEV; |
173 | flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | 173 | flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
174 | flags |= (0x800 << 18); | 174 | flags |= BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; |
175 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); | 175 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); |
176 | } else { | 176 | } else { |
177 | if (!(flags & 0x00020000)) | 177 | if (!(flags & BCM43xx_SBTMSTATEHIGH_A_PHY_AVAIL)) |
178 | return -ENODEV; | 178 | return -ENODEV; |
179 | flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); | 179 | flags = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); |
180 | flags &= ~(0x800 << 18); | 180 | flags &= ~BCM43xx_SBTMSTATELOW_G_MODE_ENABLE; |
181 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); | 181 | bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, flags); |
182 | } | 182 | } |
183 | out: | 183 | out: |
@@ -300,16 +300,20 @@ static void bcm43xx_phy_agcsetup(struct bcm43xx_private *bcm) | |||
300 | 300 | ||
301 | if (phy->rev > 2) { | 301 | if (phy->rev > 2) { |
302 | bcm43xx_phy_write(bcm, 0x0422, 0x287A); | 302 | bcm43xx_phy_write(bcm, 0x0422, 0x287A); |
303 | bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) & 0x0FFF) | 0x3000); | 303 | bcm43xx_phy_write(bcm, 0x0420, (bcm43xx_phy_read(bcm, 0x0420) |
304 | & 0x0FFF) | 0x3000); | ||
304 | } | 305 | } |
305 | 306 | ||
306 | bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) | 0x7874); | 307 | bcm43xx_phy_write(bcm, 0x04A8, (bcm43xx_phy_read(bcm, 0x04A8) & 0x8080) |
308 | | 0x7874); | ||
307 | bcm43xx_phy_write(bcm, 0x048E, 0x1C00); | 309 | bcm43xx_phy_write(bcm, 0x048E, 0x1C00); |
308 | 310 | ||
309 | if (phy->rev == 1) { | 311 | if (phy->rev == 1) { |
310 | bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) & 0xF0FF) | 0x0600); | 312 | bcm43xx_phy_write(bcm, 0x04AB, (bcm43xx_phy_read(bcm, 0x04AB) |
313 | & 0xF0FF) | 0x0600); | ||
311 | bcm43xx_phy_write(bcm, 0x048B, 0x005E); | 314 | bcm43xx_phy_write(bcm, 0x048B, 0x005E); |
312 | bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) & 0xFF00) | 0x001E); | 315 | bcm43xx_phy_write(bcm, 0x048C, (bcm43xx_phy_read(bcm, 0x048C) |
316 | & 0xFF00) | 0x001E); | ||
313 | bcm43xx_phy_write(bcm, 0x048D, 0x0002); | 317 | bcm43xx_phy_write(bcm, 0x048D, 0x0002); |
314 | } | 318 | } |
315 | 319 | ||
@@ -335,7 +339,8 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm) | |||
335 | if (phy->rev == 1) { | 339 | if (phy->rev == 1) { |
336 | bcm43xx_phy_write(bcm, 0x0406, 0x4F19); | 340 | bcm43xx_phy_write(bcm, 0x0406, 0x4F19); |
337 | bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, | 341 | bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, |
338 | (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0xFC3F) | 0x0340); | 342 | (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) |
343 | & 0xFC3F) | 0x0340); | ||
339 | bcm43xx_phy_write(bcm, 0x042C, 0x005A); | 344 | bcm43xx_phy_write(bcm, 0x042C, 0x005A); |
340 | bcm43xx_phy_write(bcm, 0x0427, 0x001A); | 345 | bcm43xx_phy_write(bcm, 0x0427, 0x001A); |
341 | 346 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h index 1f321ef42be8..73118364b552 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_phy.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_phy.h | |||
@@ -48,6 +48,10 @@ void bcm43xx_raw_phy_unlock(struct bcm43xx_private *bcm); | |||
48 | local_irq_restore(flags); \ | 48 | local_irq_restore(flags); \ |
49 | } while (0) | 49 | } while (0) |
50 | 50 | ||
51 | /* Card uses the loopback gain stuff */ | ||
52 | #define has_loopback_gain(phy) \ | ||
53 | (((phy)->rev > 1) || ((phy)->connected)) | ||
54 | |||
51 | u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset); | 55 | u16 bcm43xx_phy_read(struct bcm43xx_private *bcm, u16 offset); |
52 | void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val); | 56 | void bcm43xx_phy_write(struct bcm43xx_private *bcm, u16 offset, u16 val); |
53 | 57 | ||
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c index 4025dd0089d2..6a109f4a1b71 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_radio.c +++ b/drivers/net/wireless/bcm43xx/bcm43xx_radio.c | |||
@@ -1343,11 +1343,110 @@ u16 bcm43xx_radio_calibrationvalue(struct bcm43xx_private *bcm) | |||
1343 | return ret; | 1343 | return ret; |
1344 | } | 1344 | } |
1345 | 1345 | ||
1346 | #define LPD(L, P, D) (((L) << 2) | ((P) << 1) | ((D) << 0)) | ||
1347 | static u16 bcm43xx_get_812_value(struct bcm43xx_private *bcm, u8 lpd) | ||
1348 | { | ||
1349 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | ||
1350 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | ||
1351 | u16 loop_or = 0; | ||
1352 | u16 adj_loopback_gain = phy->loopback_gain[0]; | ||
1353 | u8 loop; | ||
1354 | u16 extern_lna_control; | ||
1355 | |||
1356 | if (!phy->connected) | ||
1357 | return 0; | ||
1358 | if (!has_loopback_gain(phy)) { | ||
1359 | if (phy->rev < 7 || !(bcm->sprom.boardflags | ||
1360 | & BCM43xx_BFL_EXTLNA)) { | ||
1361 | switch (lpd) { | ||
1362 | case LPD(0, 1, 1): | ||
1363 | return 0x0FB2; | ||
1364 | case LPD(0, 0, 1): | ||
1365 | return 0x00B2; | ||
1366 | case LPD(1, 0, 1): | ||
1367 | return 0x30B2; | ||
1368 | case LPD(1, 0, 0): | ||
1369 | return 0x30B3; | ||
1370 | default: | ||
1371 | assert(0); | ||
1372 | } | ||
1373 | } else { | ||
1374 | switch (lpd) { | ||
1375 | case LPD(0, 1, 1): | ||
1376 | return 0x8FB2; | ||
1377 | case LPD(0, 0, 1): | ||
1378 | return 0x80B2; | ||
1379 | case LPD(1, 0, 1): | ||
1380 | return 0x20B2; | ||
1381 | case LPD(1, 0, 0): | ||
1382 | return 0x20B3; | ||
1383 | default: | ||
1384 | assert(0); | ||
1385 | } | ||
1386 | } | ||
1387 | } else { | ||
1388 | if (radio->revision == 8) | ||
1389 | adj_loopback_gain += 0x003E; | ||
1390 | else | ||
1391 | adj_loopback_gain += 0x0026; | ||
1392 | if (adj_loopback_gain >= 0x46) { | ||
1393 | adj_loopback_gain -= 0x46; | ||
1394 | extern_lna_control = 0x3000; | ||
1395 | } else if (adj_loopback_gain >= 0x3A) { | ||
1396 | adj_loopback_gain -= 0x3A; | ||
1397 | extern_lna_control = 0x2000; | ||
1398 | } else if (adj_loopback_gain >= 0x2E) { | ||
1399 | adj_loopback_gain -= 0x2E; | ||
1400 | extern_lna_control = 0x1000; | ||
1401 | } else { | ||
1402 | adj_loopback_gain -= 0x10; | ||
1403 | extern_lna_control = 0x0000; | ||
1404 | } | ||
1405 | for (loop = 0; loop < 16; loop++) { | ||
1406 | u16 tmp = adj_loopback_gain - 6 * loop; | ||
1407 | if (tmp < 6) | ||
1408 | break; | ||
1409 | } | ||
1410 | |||
1411 | loop_or = (loop << 8) | extern_lna_control; | ||
1412 | if (phy->rev >= 7 && bcm->sprom.boardflags | ||
1413 | & BCM43xx_BFL_EXTLNA) { | ||
1414 | if (extern_lna_control) | ||
1415 | loop_or |= 0x8000; | ||
1416 | switch (lpd) { | ||
1417 | case LPD(0, 1, 1): | ||
1418 | return 0x8F92; | ||
1419 | case LPD(0, 0, 1): | ||
1420 | return (0x8092 | loop_or); | ||
1421 | case LPD(1, 0, 1): | ||
1422 | return (0x2092 | loop_or); | ||
1423 | case LPD(1, 0, 0): | ||
1424 | return (0x2093 | loop_or); | ||
1425 | default: | ||
1426 | assert(0); | ||
1427 | } | ||
1428 | } else { | ||
1429 | switch (lpd) { | ||
1430 | case LPD(0, 1, 1): | ||
1431 | return 0x0F92; | ||
1432 | case LPD(0, 0, 1): | ||
1433 | case LPD(1, 0, 1): | ||
1434 | return (0x0092 | loop_or); | ||
1435 | case LPD(1, 0, 0): | ||
1436 | return (0x0093 | loop_or); | ||
1437 | default: | ||
1438 | assert(0); | ||
1439 | } | ||
1440 | } | ||
1441 | } | ||
1442 | return 0; | ||
1443 | } | ||
1444 | |||
1346 | u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) | 1445 | u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) |
1347 | { | 1446 | { |
1348 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); | 1447 | struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); |
1349 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); | 1448 | struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); |
1350 | u16 backup[19] = { 0 }; | 1449 | u16 backup[21] = { 0 }; |
1351 | u16 ret; | 1450 | u16 ret; |
1352 | u16 i, j; | 1451 | u16 i, j; |
1353 | u32 tmp1 = 0, tmp2 = 0; | 1452 | u32 tmp1 = 0, tmp2 = 0; |
@@ -1373,19 +1472,36 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) | |||
1373 | backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); | 1472 | backup[8] = bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS); |
1374 | backup[9] = bcm43xx_phy_read(bcm, 0x0802); | 1473 | backup[9] = bcm43xx_phy_read(bcm, 0x0802); |
1375 | bcm43xx_phy_write(bcm, 0x0814, | 1474 | bcm43xx_phy_write(bcm, 0x0814, |
1376 | (bcm43xx_phy_read(bcm, 0x0814) | 0x0003)); | 1475 | (bcm43xx_phy_read(bcm, 0x0814) |
1476 | | 0x0003)); | ||
1377 | bcm43xx_phy_write(bcm, 0x0815, | 1477 | bcm43xx_phy_write(bcm, 0x0815, |
1378 | (bcm43xx_phy_read(bcm, 0x0815) & 0xFFFC)); | 1478 | (bcm43xx_phy_read(bcm, 0x0815) |
1479 | & 0xFFFC)); | ||
1379 | bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, | 1480 | bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, |
1380 | (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) & 0x7FFF)); | 1481 | (bcm43xx_phy_read(bcm, BCM43xx_PHY_G_CRS) |
1482 | & 0x7FFF)); | ||
1381 | bcm43xx_phy_write(bcm, 0x0802, | 1483 | bcm43xx_phy_write(bcm, 0x0802, |
1382 | (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); | 1484 | (bcm43xx_phy_read(bcm, 0x0802) & 0xFFFC)); |
1383 | bcm43xx_phy_write(bcm, 0x0811, 0x01B3); | 1485 | if (phy->rev > 1) { /* loopback gain enabled */ |
1384 | bcm43xx_phy_write(bcm, 0x0812, 0x0FB2); | 1486 | backup[19] = bcm43xx_phy_read(bcm, 0x080F); |
1487 | backup[20] = bcm43xx_phy_read(bcm, 0x0810); | ||
1488 | if (phy->rev >= 3) | ||
1489 | bcm43xx_phy_write(bcm, 0x080F, 0xC020); | ||
1490 | else | ||
1491 | bcm43xx_phy_write(bcm, 0x080F, 0x8020); | ||
1492 | bcm43xx_phy_write(bcm, 0x0810, 0x0000); | ||
1493 | } | ||
1494 | bcm43xx_phy_write(bcm, 0x0812, | ||
1495 | bcm43xx_get_812_value(bcm, LPD(0, 1, 1))); | ||
1496 | if (phy->rev < 7 || !(bcm->sprom.boardflags | ||
1497 | & BCM43xx_BFL_EXTLNA)) | ||
1498 | bcm43xx_phy_write(bcm, 0x0811, 0x01B3); | ||
1499 | else | ||
1500 | bcm43xx_phy_write(bcm, 0x0811, 0x09B3); | ||
1385 | } | 1501 | } |
1386 | bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, | ||
1387 | (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); | ||
1388 | } | 1502 | } |
1503 | bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, | ||
1504 | (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) | 0x8000)); | ||
1389 | backup[10] = bcm43xx_phy_read(bcm, 0x0035); | 1505 | backup[10] = bcm43xx_phy_read(bcm, 0x0035); |
1390 | bcm43xx_phy_write(bcm, 0x0035, | 1506 | bcm43xx_phy_write(bcm, 0x0035, |
1391 | (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); | 1507 | (bcm43xx_phy_read(bcm, 0x0035) & 0xFF7F)); |
@@ -1397,10 +1513,12 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) | |||
1397 | bcm43xx_write16(bcm, 0x03E6, 0x0122); | 1513 | bcm43xx_write16(bcm, 0x03E6, 0x0122); |
1398 | } else { | 1514 | } else { |
1399 | if (phy->analog >= 2) | 1515 | if (phy->analog >= 2) |
1400 | bcm43xx_phy_write(bcm, 0x0003, (bcm43xx_phy_read(bcm, 0x0003) | 1516 | bcm43xx_phy_write(bcm, 0x0003, |
1401 | & 0xFFBF) | 0x0040); | 1517 | (bcm43xx_phy_read(bcm, 0x0003) |
1518 | & 0xFFBF) | 0x0040); | ||
1402 | bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, | 1519 | bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, |
1403 | (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | 0x2000)); | 1520 | (bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) |
1521 | | 0x2000)); | ||
1404 | } | 1522 | } |
1405 | 1523 | ||
1406 | ret = bcm43xx_radio_calibrationvalue(bcm); | 1524 | ret = bcm43xx_radio_calibrationvalue(bcm); |
@@ -1408,16 +1526,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) | |||
1408 | if (phy->type == BCM43xx_PHYTYPE_B) | 1526 | if (phy->type == BCM43xx_PHYTYPE_B) |
1409 | bcm43xx_radio_write16(bcm, 0x0078, 0x0026); | 1527 | bcm43xx_radio_write16(bcm, 0x0078, 0x0026); |
1410 | 1528 | ||
1529 | if (phy->connected) | ||
1530 | bcm43xx_phy_write(bcm, 0x0812, | ||
1531 | bcm43xx_get_812_value(bcm, LPD(0, 1, 1))); | ||
1411 | bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); | 1532 | bcm43xx_phy_write(bcm, 0x0015, 0xBFAF); |
1412 | bcm43xx_phy_write(bcm, 0x002B, 0x1403); | 1533 | bcm43xx_phy_write(bcm, 0x002B, 0x1403); |
1413 | if (phy->connected) | 1534 | if (phy->connected) |
1414 | bcm43xx_phy_write(bcm, 0x0812, 0x00B2); | 1535 | bcm43xx_phy_write(bcm, 0x0812, |
1536 | bcm43xx_get_812_value(bcm, LPD(0, 0, 1))); | ||
1415 | bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); | 1537 | bcm43xx_phy_write(bcm, 0x0015, 0xBFA0); |
1416 | bcm43xx_radio_write16(bcm, 0x0051, | 1538 | bcm43xx_radio_write16(bcm, 0x0051, |
1417 | (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); | 1539 | (bcm43xx_radio_read16(bcm, 0x0051) | 0x0004)); |
1418 | bcm43xx_radio_write16(bcm, 0x0052, 0x0000); | 1540 | if (radio->revision == 8) |
1419 | bcm43xx_radio_write16(bcm, 0x0043, | 1541 | bcm43xx_radio_write16(bcm, 0x0043, 0x001F); |
1420 | (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | 0x0009); | 1542 | else { |
1543 | bcm43xx_radio_write16(bcm, 0x0052, 0x0000); | ||
1544 | bcm43xx_radio_write16(bcm, 0x0043, | ||
1545 | (bcm43xx_radio_read16(bcm, 0x0043) & 0xFFF0) | ||
1546 | | 0x0009); | ||
1547 | } | ||
1421 | bcm43xx_phy_write(bcm, 0x0058, 0x0000); | 1548 | bcm43xx_phy_write(bcm, 0x0058, 0x0000); |
1422 | 1549 | ||
1423 | for (i = 0; i < 16; i++) { | 1550 | for (i = 0; i < 16; i++) { |
@@ -1425,21 +1552,25 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) | |||
1425 | bcm43xx_phy_write(bcm, 0x0059, 0xC810); | 1552 | bcm43xx_phy_write(bcm, 0x0059, 0xC810); |
1426 | bcm43xx_phy_write(bcm, 0x0058, 0x000D); | 1553 | bcm43xx_phy_write(bcm, 0x0058, 0x000D); |
1427 | if (phy->connected) | 1554 | if (phy->connected) |
1428 | bcm43xx_phy_write(bcm, 0x0812, 0x30B2); | 1555 | bcm43xx_phy_write(bcm, 0x0812, |
1556 | bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); | ||
1429 | bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); | 1557 | bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); |
1430 | udelay(10); | 1558 | udelay(10); |
1431 | if (phy->connected) | 1559 | if (phy->connected) |
1432 | bcm43xx_phy_write(bcm, 0x0812, 0x30B2); | 1560 | bcm43xx_phy_write(bcm, 0x0812, |
1561 | bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); | ||
1433 | bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); | 1562 | bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); |
1434 | udelay(10); | 1563 | udelay(10); |
1435 | if (phy->connected) | 1564 | if (phy->connected) |
1436 | bcm43xx_phy_write(bcm, 0x0812, 0x30B2); | 1565 | bcm43xx_phy_write(bcm, 0x0812, |
1566 | bcm43xx_get_812_value(bcm, LPD(1, 0, 0))); | ||
1437 | bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); | 1567 | bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); |
1438 | udelay(10); | 1568 | udelay(20); |
1439 | tmp1 += bcm43xx_phy_read(bcm, 0x002D); | 1569 | tmp1 += bcm43xx_phy_read(bcm, 0x002D); |
1440 | bcm43xx_phy_write(bcm, 0x0058, 0x0000); | 1570 | bcm43xx_phy_write(bcm, 0x0058, 0x0000); |
1441 | if (phy->connected) | 1571 | if (phy->connected) |
1442 | bcm43xx_phy_write(bcm, 0x0812, 0x30B2); | 1572 | bcm43xx_phy_write(bcm, 0x0812, |
1573 | bcm43xx_get_812_value(bcm, LPD(1, 0, 1))); | ||
1443 | bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); | 1574 | bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); |
1444 | } | 1575 | } |
1445 | 1576 | ||
@@ -1457,21 +1588,29 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) | |||
1457 | bcm43xx_phy_write(bcm, 0x0059, 0xC810); | 1588 | bcm43xx_phy_write(bcm, 0x0059, 0xC810); |
1458 | bcm43xx_phy_write(bcm, 0x0058, 0x000D); | 1589 | bcm43xx_phy_write(bcm, 0x0058, 0x000D); |
1459 | if (phy->connected) | 1590 | if (phy->connected) |
1460 | bcm43xx_phy_write(bcm, 0x0812, 0x30B2); | 1591 | bcm43xx_phy_write(bcm, 0x0812, |
1592 | bcm43xx_get_812_value(bcm, | ||
1593 | LPD(1, 0, 1))); | ||
1461 | bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); | 1594 | bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); |
1462 | udelay(10); | 1595 | udelay(10); |
1463 | if (phy->connected) | 1596 | if (phy->connected) |
1464 | bcm43xx_phy_write(bcm, 0x0812, 0x30B2); | 1597 | bcm43xx_phy_write(bcm, 0x0812, |
1598 | bcm43xx_get_812_value(bcm, | ||
1599 | LPD(1, 0, 1))); | ||
1465 | bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); | 1600 | bcm43xx_phy_write(bcm, 0x0015, 0xEFB0); |
1466 | udelay(10); | 1601 | udelay(10); |
1467 | if (phy->connected) | 1602 | if (phy->connected) |
1468 | bcm43xx_phy_write(bcm, 0x0812, 0x30B3); /* 0x30B3 is not a typo */ | 1603 | bcm43xx_phy_write(bcm, 0x0812, |
1604 | bcm43xx_get_812_value(bcm, | ||
1605 | LPD(1, 0, 0))); | ||
1469 | bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); | 1606 | bcm43xx_phy_write(bcm, 0x0015, 0xFFF0); |
1470 | udelay(10); | 1607 | udelay(10); |
1471 | tmp2 += bcm43xx_phy_read(bcm, 0x002D); | 1608 | tmp2 += bcm43xx_phy_read(bcm, 0x002D); |
1472 | bcm43xx_phy_write(bcm, 0x0058, 0x0000); | 1609 | bcm43xx_phy_write(bcm, 0x0058, 0x0000); |
1473 | if (phy->connected) | 1610 | if (phy->connected) |
1474 | bcm43xx_phy_write(bcm, 0x0812, 0x30B2); | 1611 | bcm43xx_phy_write(bcm, 0x0812, |
1612 | bcm43xx_get_812_value(bcm, | ||
1613 | LPD(1, 0, 1))); | ||
1475 | bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); | 1614 | bcm43xx_phy_write(bcm, 0x0015, 0xAFB0); |
1476 | } | 1615 | } |
1477 | tmp2++; | 1616 | tmp2++; |
@@ -1497,15 +1636,20 @@ u16 bcm43xx_radio_init2050(struct bcm43xx_private *bcm) | |||
1497 | bcm43xx_phy_write(bcm, 0x0030, backup[2]); | 1636 | bcm43xx_phy_write(bcm, 0x0030, backup[2]); |
1498 | bcm43xx_write16(bcm, 0x03EC, backup[3]); | 1637 | bcm43xx_write16(bcm, 0x03EC, backup[3]); |
1499 | } else { | 1638 | } else { |
1500 | bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, | ||
1501 | (bcm43xx_read16(bcm, BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); | ||
1502 | if (phy->connected) { | 1639 | if (phy->connected) { |
1640 | bcm43xx_write16(bcm, BCM43xx_MMIO_PHY_RADIO, | ||
1641 | (bcm43xx_read16(bcm, | ||
1642 | BCM43xx_MMIO_PHY_RADIO) & 0x7FFF)); | ||
1503 | bcm43xx_phy_write(bcm, 0x0811, backup[4]); | 1643 | bcm43xx_phy_write(bcm, 0x0811, backup[4]); |
1504 | bcm43xx_phy_write(bcm, 0x0812, backup[5]); | 1644 | bcm43xx_phy_write(bcm, 0x0812, backup[5]); |
1505 | bcm43xx_phy_write(bcm, 0x0814, backup[6]); | 1645 | bcm43xx_phy_write(bcm, 0x0814, backup[6]); |
1506 | bcm43xx_phy_write(bcm, 0x0815, backup[7]); | 1646 | bcm43xx_phy_write(bcm, 0x0815, backup[7]); |
1507 | bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); | 1647 | bcm43xx_phy_write(bcm, BCM43xx_PHY_G_CRS, backup[8]); |
1508 | bcm43xx_phy_write(bcm, 0x0802, backup[9]); | 1648 | bcm43xx_phy_write(bcm, 0x0802, backup[9]); |
1649 | if (phy->rev > 1) { | ||
1650 | bcm43xx_phy_write(bcm, 0x080F, backup[19]); | ||
1651 | bcm43xx_phy_write(bcm, 0x0810, backup[20]); | ||
1652 | } | ||
1509 | } | 1653 | } |
1510 | } | 1654 | } |
1511 | if (i >= 15) | 1655 | if (i >= 15) |
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index 4ca8a27b8c55..5b3abd54d0e5 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c | |||
@@ -1,8 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * Intersil Prism2 driver with Host AP (software access point) support | 2 | * Intersil Prism2 driver with Host AP (software access point) support |
3 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | 3 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen |
4 | * <jkmaline@cc.hut.fi> | 4 | * <j@w1.fi> |
5 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | 5 | * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> |
6 | * | 6 | * |
7 | * This file is to be included into hostap.c when S/W AP functionality is | 7 | * This file is to be included into hostap.c when S/W AP functionality is |
8 | * compiled. | 8 | * compiled. |
diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index 01624005d808..b31e6a05f23c 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h | |||
@@ -368,9 +368,9 @@ enum { | |||
368 | 368 | ||
369 | #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 | 369 | #define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024 |
370 | #define PRISM2_HOSTAPD_RID_HDR_LEN \ | 370 | #define PRISM2_HOSTAPD_RID_HDR_LEN \ |
371 | ((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data)) | 371 | offsetof(struct prism2_hostapd_param, u.rid.data) |
372 | #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ | 372 | #define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \ |
373 | ((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data)) | 373 | offsetof(struct prism2_hostapd_param, u.generic_elem.data) |
374 | 374 | ||
375 | /* Maximum length for algorithm names (-1 for nul termination) used in ioctl() | 375 | /* Maximum length for algorithm names (-1 for nul termination) used in ioctl() |
376 | */ | 376 | */ |
diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c index 8d8f4b9b8b07..ee1532b62e42 100644 --- a/drivers/net/wireless/hostap/hostap_cs.c +++ b/drivers/net/wireless/hostap/hostap_cs.c | |||
@@ -22,7 +22,7 @@ | |||
22 | #include "hostap_wlan.h" | 22 | #include "hostap_wlan.h" |
23 | 23 | ||
24 | 24 | ||
25 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | 25 | static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)"; |
26 | static dev_info_t dev_info = "hostap_cs"; | 26 | static dev_info_t dev_info = "hostap_cs"; |
27 | 27 | ||
28 | MODULE_AUTHOR("Jouni Malinen"); | 28 | MODULE_AUTHOR("Jouni Malinen"); |
@@ -838,6 +838,8 @@ static struct pcmcia_device_id hostap_cs_ids[] = { | |||
838 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), | 838 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005), |
839 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), | 839 | PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0010), |
840 | PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), | 840 | PCMCIA_DEVICE_MANF_CARD(0x0126, 0x0002), |
841 | PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0xd601, 0x0005, "ADLINK 345 CF", | ||
842 | 0x2d858104), | ||
841 | PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", | 843 | PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "INTERSIL", |
842 | 0x74c5e40d), | 844 | 0x74c5e40d), |
843 | PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", | 845 | PCMCIA_DEVICE_MANF_CARD_PROD_ID1(0x0156, 0x0002, "Intersil", |
@@ -848,6 +850,11 @@ static struct pcmcia_device_id hostap_cs_ids[] = { | |||
848 | "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", | 850 | "Intersil", "PRISM 2_5 PCMCIA ADAPTER", "ISL37300P", |
849 | "Eval-RevA", | 851 | "Eval-RevA", |
850 | 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e), | 852 | 0x4b801a17, 0x6345a0bf, 0xc9049a39, 0xc23adc0e), |
853 | /* D-Link DWL-650 Rev. P1; manfid 0x000b, 0x7110 */ | ||
854 | PCMCIA_DEVICE_PROD_ID1234( | ||
855 | "D-Link", "DWL-650 Wireless PC Card RevP", "ISL37101P-10", | ||
856 | "A3", | ||
857 | 0x1a424a1c, 0x6ea57632, 0xdd97a26b, 0x56b21f52), | ||
851 | PCMCIA_DEVICE_PROD_ID123( | 858 | PCMCIA_DEVICE_PROD_ID123( |
852 | "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", | 859 | "Addtron", "AWP-100 Wireless PCMCIA", "Version 01.02", |
853 | 0xe6ec52ce, 0x08649af2, 0x4b74baa0), | 860 | 0xe6ec52ce, 0x08649af2, 0x4b74baa0), |
diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index fb01fb95a9f0..959887b70ca7 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c | |||
@@ -3,8 +3,8 @@ | |||
3 | * Intersil Prism2/2.5/3. | 3 | * Intersil Prism2/2.5/3. |
4 | * | 4 | * |
5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | 5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen |
6 | * <jkmaline@cc.hut.fi> | 6 | * <j@w1.fi> |
7 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | 7 | * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 1f9edd91565d..4743426cf6ad 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c | |||
@@ -3,8 +3,8 @@ | |||
3 | * Intersil Prism2/2.5/3 - hostap.o module, common routines | 3 | * Intersil Prism2/2.5/3 - hostap.o module, common routines |
4 | * | 4 | * |
5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | 5 | * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen |
6 | * <jkmaline@cc.hut.fi> | 6 | * <j@w1.fi> |
7 | * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi> | 7 | * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as | 10 | * it under the terms of the GNU General Public License version 2 as |
diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index c4f6020baa9e..db4899ed4bb1 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include "hostap_wlan.h" | 20 | #include "hostap_wlan.h" |
21 | 21 | ||
22 | 22 | ||
23 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | 23 | static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)"; |
24 | static char *dev_info = "hostap_pci"; | 24 | static char *dev_info = "hostap_pci"; |
25 | 25 | ||
26 | 26 | ||
diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c index e235e0647897..f0fd5ecdb24d 100644 --- a/drivers/net/wireless/hostap/hostap_plx.c +++ b/drivers/net/wireless/hostap/hostap_plx.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include "hostap_wlan.h" | 23 | #include "hostap_wlan.h" |
24 | 24 | ||
25 | 25 | ||
26 | static char *version = PRISM2_VERSION " (Jouni Malinen <jkmaline@cc.hut.fi>)"; | 26 | static char *version = PRISM2_VERSION " (Jouni Malinen <j@w1.fi>)"; |
27 | static char *dev_info = "hostap_plx"; | 27 | static char *dev_info = "hostap_plx"; |
28 | 28 | ||
29 | 29 | ||
diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index 9137a4dd02eb..d51daf87450f 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c | |||
@@ -28,8 +28,8 @@ | |||
28 | 28 | ||
29 | Portions of this file are based on the Host AP project, | 29 | Portions of this file are based on the Host AP project, |
30 | Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen | 30 | Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen |
31 | <jkmaline@cc.hut.fi> | 31 | <j@w1.fi> |
32 | Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi> | 32 | Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi> |
33 | 33 | ||
34 | Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and | 34 | Portions of ipw2100_mod_firmware_load, ipw2100_do_mod_firmware_load, and |
35 | ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c | 35 | ipw2100_fw_load are loosely based on drivers/sound/sound_firmware.c |
diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2200.c index 4839a45098cb..7cb2052a55a5 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2200.c | |||
@@ -1847,6 +1847,52 @@ static ssize_t store_net_stats(struct device *d, struct device_attribute *attr, | |||
1847 | static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, | 1847 | static DEVICE_ATTR(net_stats, S_IWUSR | S_IRUGO, |
1848 | show_net_stats, store_net_stats); | 1848 | show_net_stats, store_net_stats); |
1849 | 1849 | ||
1850 | static ssize_t show_channels(struct device *d, | ||
1851 | struct device_attribute *attr, | ||
1852 | char *buf) | ||
1853 | { | ||
1854 | struct ipw_priv *priv = dev_get_drvdata(d); | ||
1855 | const struct ieee80211_geo *geo = ieee80211_get_geo(priv->ieee); | ||
1856 | int len = 0, i; | ||
1857 | |||
1858 | len = sprintf(&buf[len], | ||
1859 | "Displaying %d channels in 2.4Ghz band " | ||
1860 | "(802.11bg):\n", geo->bg_channels); | ||
1861 | |||
1862 | for (i = 0; i < geo->bg_channels; i++) { | ||
1863 | len += sprintf(&buf[len], "%d: BSS%s%s, %s, Band %s.\n", | ||
1864 | geo->bg[i].channel, | ||
1865 | geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT ? | ||
1866 | " (radar spectrum)" : "", | ||
1867 | ((geo->bg[i].flags & IEEE80211_CH_NO_IBSS) || | ||
1868 | (geo->bg[i].flags & IEEE80211_CH_RADAR_DETECT)) | ||
1869 | ? "" : ", IBSS", | ||
1870 | geo->bg[i].flags & IEEE80211_CH_PASSIVE_ONLY ? | ||
1871 | "passive only" : "active/passive", | ||
1872 | geo->bg[i].flags & IEEE80211_CH_B_ONLY ? | ||
1873 | "B" : "B/G"); | ||
1874 | } | ||
1875 | |||
1876 | len += sprintf(&buf[len], | ||
1877 | "Displaying %d channels in 5.2Ghz band " | ||
1878 | "(802.11a):\n", geo->a_channels); | ||
1879 | for (i = 0; i < geo->a_channels; i++) { | ||
1880 | len += sprintf(&buf[len], "%d: BSS%s%s, %s.\n", | ||
1881 | geo->a[i].channel, | ||
1882 | geo->a[i].flags & IEEE80211_CH_RADAR_DETECT ? | ||
1883 | " (radar spectrum)" : "", | ||
1884 | ((geo->a[i].flags & IEEE80211_CH_NO_IBSS) || | ||
1885 | (geo->a[i].flags & IEEE80211_CH_RADAR_DETECT)) | ||
1886 | ? "" : ", IBSS", | ||
1887 | geo->a[i].flags & IEEE80211_CH_PASSIVE_ONLY ? | ||
1888 | "passive only" : "active/passive"); | ||
1889 | } | ||
1890 | |||
1891 | return len; | ||
1892 | } | ||
1893 | |||
1894 | static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); | ||
1895 | |||
1850 | static void notify_wx_assoc_event(struct ipw_priv *priv) | 1896 | static void notify_wx_assoc_event(struct ipw_priv *priv) |
1851 | { | 1897 | { |
1852 | union iwreq_data wrqu; | 1898 | union iwreq_data wrqu; |
@@ -11383,6 +11429,7 @@ static struct attribute *ipw_sysfs_entries[] = { | |||
11383 | &dev_attr_led.attr, | 11429 | &dev_attr_led.attr, |
11384 | &dev_attr_speed_scan.attr, | 11430 | &dev_attr_speed_scan.attr, |
11385 | &dev_attr_net_stats.attr, | 11431 | &dev_attr_net_stats.attr, |
11432 | &dev_attr_channels.attr, | ||
11386 | #ifdef CONFIG_IPW2200_PROMISCUOUS | 11433 | #ifdef CONFIG_IPW2200_PROMISCUOUS |
11387 | &dev_attr_rtap_iface.attr, | 11434 | &dev_attr_rtap_iface.attr, |
11388 | &dev_attr_rtap_filter.attr, | 11435 | &dev_attr_rtap_filter.attr, |
diff --git a/drivers/net/wireless/libertas/11d.c b/drivers/net/wireless/libertas/11d.c new file mode 100644 index 000000000000..e0ecc4d483bb --- /dev/null +++ b/drivers/net/wireless/libertas/11d.c | |||
@@ -0,0 +1,754 @@ | |||
1 | /** | ||
2 | * This file contains functions for 802.11D. | ||
3 | */ | ||
4 | #include <linux/ctype.h> | ||
5 | #include <linux/kernel.h> | ||
6 | #include <linux/wireless.h> | ||
7 | |||
8 | #include "host.h" | ||
9 | #include "decl.h" | ||
10 | #include "11d.h" | ||
11 | #include "dev.h" | ||
12 | #include "wext.h" | ||
13 | |||
14 | #define TX_PWR_DEFAULT 10 | ||
15 | |||
16 | static struct region_code_mapping region_code_mapping[] = { | ||
17 | {"US ", 0x10}, /* US FCC */ | ||
18 | {"CA ", 0x10}, /* IC Canada */ | ||
19 | {"SG ", 0x10}, /* Singapore */ | ||
20 | {"EU ", 0x30}, /* ETSI */ | ||
21 | {"AU ", 0x30}, /* Australia */ | ||
22 | {"KR ", 0x30}, /* Republic Of Korea */ | ||
23 | {"ES ", 0x31}, /* Spain */ | ||
24 | {"FR ", 0x32}, /* France */ | ||
25 | {"JP ", 0x40}, /* Japan */ | ||
26 | }; | ||
27 | |||
28 | /* Following 2 structure defines the supported channels */ | ||
29 | static struct chan_freq_power channel_freq_power_UN_BG[] = { | ||
30 | {1, 2412, TX_PWR_DEFAULT}, | ||
31 | {2, 2417, TX_PWR_DEFAULT}, | ||
32 | {3, 2422, TX_PWR_DEFAULT}, | ||
33 | {4, 2427, TX_PWR_DEFAULT}, | ||
34 | {5, 2432, TX_PWR_DEFAULT}, | ||
35 | {6, 2437, TX_PWR_DEFAULT}, | ||
36 | {7, 2442, TX_PWR_DEFAULT}, | ||
37 | {8, 2447, TX_PWR_DEFAULT}, | ||
38 | {9, 2452, TX_PWR_DEFAULT}, | ||
39 | {10, 2457, TX_PWR_DEFAULT}, | ||
40 | {11, 2462, TX_PWR_DEFAULT}, | ||
41 | {12, 2467, TX_PWR_DEFAULT}, | ||
42 | {13, 2472, TX_PWR_DEFAULT}, | ||
43 | {14, 2484, TX_PWR_DEFAULT} | ||
44 | }; | ||
45 | |||
46 | static u8 wlan_region_2_code(u8 * region) | ||
47 | { | ||
48 | u8 i; | ||
49 | u8 size = sizeof(region_code_mapping)/ | ||
50 | sizeof(struct region_code_mapping); | ||
51 | |||
52 | for (i = 0; region[i] && i < COUNTRY_CODE_LEN; i++) | ||
53 | region[i] = toupper(region[i]); | ||
54 | |||
55 | for (i = 0; i < size; i++) { | ||
56 | if (!memcmp(region, region_code_mapping[i].region, | ||
57 | COUNTRY_CODE_LEN)) | ||
58 | return (region_code_mapping[i].code); | ||
59 | } | ||
60 | |||
61 | /* default is US */ | ||
62 | return (region_code_mapping[0].code); | ||
63 | } | ||
64 | |||
65 | static u8 *wlan_code_2_region(u8 code) | ||
66 | { | ||
67 | u8 i; | ||
68 | u8 size = sizeof(region_code_mapping) | ||
69 | / sizeof(struct region_code_mapping); | ||
70 | for (i = 0; i < size; i++) { | ||
71 | if (region_code_mapping[i].code == code) | ||
72 | return (region_code_mapping[i].region); | ||
73 | } | ||
74 | /* default is US */ | ||
75 | return (region_code_mapping[0].region); | ||
76 | } | ||
77 | |||
78 | /** | ||
79 | * @brief This function finds the nrchan-th chan after the firstchan | ||
80 | * @param band band | ||
81 | * @param firstchan first channel number | ||
82 | * @param nrchan number of channels | ||
83 | * @return the nrchan-th chan number | ||
84 | */ | ||
85 | static u8 wlan_get_chan_11d(u8 band, u8 firstchan, u8 nrchan, u8 * chan) | ||
86 | /*find the nrchan-th chan after the firstchan*/ | ||
87 | { | ||
88 | u8 i; | ||
89 | struct chan_freq_power *cfp; | ||
90 | u8 cfp_no; | ||
91 | |||
92 | cfp = channel_freq_power_UN_BG; | ||
93 | cfp_no = sizeof(channel_freq_power_UN_BG) / | ||
94 | sizeof(struct chan_freq_power); | ||
95 | |||
96 | for (i = 0; i < cfp_no; i++) { | ||
97 | if ((cfp + i)->channel == firstchan) { | ||
98 | lbs_pr_debug(1, "firstchan found\n"); | ||
99 | break; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | if (i < cfp_no) { | ||
104 | /*if beyond the boundary */ | ||
105 | if (i + nrchan < cfp_no) { | ||
106 | *chan = (cfp + i + nrchan)->channel; | ||
107 | return 1; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | /** | ||
115 | * @brief This function Checks if chan txpwr is learned from AP/IBSS | ||
116 | * @param chan chan number | ||
117 | * @param parsed_region_chan pointer to parsed_region_chan_11d | ||
118 | * @return TRUE; FALSE | ||
119 | */ | ||
120 | static u8 wlan_channel_known_11d(u8 chan, | ||
121 | struct parsed_region_chan_11d * parsed_region_chan) | ||
122 | { | ||
123 | struct chan_power_11d *chanpwr = parsed_region_chan->chanpwr; | ||
124 | u8 nr_chan = parsed_region_chan->nr_chan; | ||
125 | u8 i = 0; | ||
126 | |||
127 | lbs_dbg_hex("11D:parsed_region_chan:", (char *)chanpwr, | ||
128 | sizeof(struct chan_power_11d) * nr_chan); | ||
129 | |||
130 | for (i = 0; i < nr_chan; i++) { | ||
131 | if (chan == chanpwr[i].chan) { | ||
132 | lbs_pr_debug(1, "11D: Found Chan:%d\n", chan); | ||
133 | return 1; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | lbs_pr_debug(1, "11D: Not Find Chan:%d\n", chan); | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | u32 libertas_chan_2_freq(u8 chan, u8 band) | ||
142 | { | ||
143 | struct chan_freq_power *cf; | ||
144 | u16 cnt; | ||
145 | u16 i; | ||
146 | u32 freq = 0; | ||
147 | |||
148 | cf = channel_freq_power_UN_BG; | ||
149 | cnt = | ||
150 | sizeof(channel_freq_power_UN_BG) / | ||
151 | sizeof(struct chan_freq_power); | ||
152 | |||
153 | for (i = 0; i < cnt; i++) { | ||
154 | if (chan == cf[i].channel) | ||
155 | freq = cf[i].freq; | ||
156 | } | ||
157 | |||
158 | return freq; | ||
159 | } | ||
160 | |||
161 | static int generate_domain_info_11d(struct parsed_region_chan_11d | ||
162 | *parsed_region_chan, | ||
163 | struct wlan_802_11d_domain_reg * domaininfo) | ||
164 | { | ||
165 | u8 nr_subband = 0; | ||
166 | |||
167 | u8 nr_chan = parsed_region_chan->nr_chan; | ||
168 | u8 nr_parsedchan = 0; | ||
169 | |||
170 | u8 firstchan = 0, nextchan = 0, maxpwr = 0; | ||
171 | |||
172 | u8 i, flag = 0; | ||
173 | |||
174 | memcpy(domaininfo->countrycode, parsed_region_chan->countrycode, | ||
175 | COUNTRY_CODE_LEN); | ||
176 | |||
177 | lbs_pr_debug(1, "11D:nrchan=%d\n", nr_chan); | ||
178 | lbs_dbg_hex("11D:parsed_region_chan:", (char *)parsed_region_chan, | ||
179 | sizeof(struct parsed_region_chan_11d)); | ||
180 | |||
181 | for (i = 0; i < nr_chan; i++) { | ||
182 | if (!flag) { | ||
183 | flag = 1; | ||
184 | nextchan = firstchan = | ||
185 | parsed_region_chan->chanpwr[i].chan; | ||
186 | maxpwr = parsed_region_chan->chanpwr[i].pwr; | ||
187 | nr_parsedchan = 1; | ||
188 | continue; | ||
189 | } | ||
190 | |||
191 | if (parsed_region_chan->chanpwr[i].chan == nextchan + 1 && | ||
192 | parsed_region_chan->chanpwr[i].pwr == maxpwr) { | ||
193 | nextchan++; | ||
194 | nr_parsedchan++; | ||
195 | } else { | ||
196 | domaininfo->subband[nr_subband].firstchan = firstchan; | ||
197 | domaininfo->subband[nr_subband].nrchan = | ||
198 | nr_parsedchan; | ||
199 | domaininfo->subband[nr_subband].maxtxpwr = maxpwr; | ||
200 | nr_subband++; | ||
201 | nextchan = firstchan = | ||
202 | parsed_region_chan->chanpwr[i].chan; | ||
203 | maxpwr = parsed_region_chan->chanpwr[i].pwr; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | if (flag) { | ||
208 | domaininfo->subband[nr_subband].firstchan = firstchan; | ||
209 | domaininfo->subband[nr_subband].nrchan = nr_parsedchan; | ||
210 | domaininfo->subband[nr_subband].maxtxpwr = maxpwr; | ||
211 | nr_subband++; | ||
212 | } | ||
213 | domaininfo->nr_subband = nr_subband; | ||
214 | |||
215 | lbs_pr_debug(1, "nr_subband=%x\n", domaininfo->nr_subband); | ||
216 | lbs_dbg_hex("11D:domaininfo:", (char *)domaininfo, | ||
217 | COUNTRY_CODE_LEN + 1 + | ||
218 | sizeof(struct ieeetypes_subbandset) * nr_subband); | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * @brief This function generates parsed_region_chan from Domain Info learned from AP/IBSS | ||
224 | * @param region_chan pointer to struct region_channel | ||
225 | * @param *parsed_region_chan pointer to parsed_region_chan_11d | ||
226 | * @return N/A | ||
227 | */ | ||
228 | static void wlan_generate_parsed_region_chan_11d(struct region_channel * region_chan, | ||
229 | struct parsed_region_chan_11d * | ||
230 | parsed_region_chan) | ||
231 | { | ||
232 | u8 i; | ||
233 | struct chan_freq_power *cfp; | ||
234 | |||
235 | if (region_chan == NULL) { | ||
236 | lbs_pr_debug(1, "11D: region_chan is NULL\n"); | ||
237 | return; | ||
238 | } | ||
239 | |||
240 | cfp = region_chan->CFP; | ||
241 | if (cfp == NULL) { | ||
242 | lbs_pr_debug(1, "11D: cfp equal NULL \n"); | ||
243 | return; | ||
244 | } | ||
245 | |||
246 | parsed_region_chan->band = region_chan->band; | ||
247 | parsed_region_chan->region = region_chan->region; | ||
248 | memcpy(parsed_region_chan->countrycode, | ||
249 | wlan_code_2_region(region_chan->region), COUNTRY_CODE_LEN); | ||
250 | |||
251 | lbs_pr_debug(1, "11D: region[0x%x] band[%d]\n", parsed_region_chan->region, | ||
252 | parsed_region_chan->band); | ||
253 | |||
254 | for (i = 0; i < region_chan->nrcfp; i++, cfp++) { | ||
255 | parsed_region_chan->chanpwr[i].chan = cfp->channel; | ||
256 | parsed_region_chan->chanpwr[i].pwr = cfp->maxtxpower; | ||
257 | lbs_pr_debug(1, "11D: Chan[%d] Pwr[%d]\n", | ||
258 | parsed_region_chan->chanpwr[i].chan, | ||
259 | parsed_region_chan->chanpwr[i].pwr); | ||
260 | } | ||
261 | parsed_region_chan->nr_chan = region_chan->nrcfp; | ||
262 | |||
263 | lbs_pr_debug(1, "11D: nrchan[%d]\n", parsed_region_chan->nr_chan); | ||
264 | |||
265 | return; | ||
266 | } | ||
267 | |||
268 | /** | ||
269 | * @brief generate parsed_region_chan from Domain Info learned from AP/IBSS | ||
270 | * @param region region ID | ||
271 | * @param band band | ||
272 | * @param chan chan | ||
273 | * @return TRUE;FALSE | ||
274 | */ | ||
275 | static u8 wlan_region_chan_supported_11d(u8 region, u8 band, u8 chan) | ||
276 | { | ||
277 | struct chan_freq_power *cfp; | ||
278 | int cfp_no; | ||
279 | u8 idx; | ||
280 | |||
281 | ENTER(); | ||
282 | |||
283 | cfp = libertas_get_region_cfp_table(region, band, &cfp_no); | ||
284 | if (cfp == NULL) | ||
285 | return 0; | ||
286 | |||
287 | for (idx = 0; idx < cfp_no; idx++) { | ||
288 | if (chan == (cfp + idx)->channel) { | ||
289 | /* If Mrvl Chip Supported? */ | ||
290 | if ((cfp + idx)->unsupported) { | ||
291 | return 0; | ||
292 | } else { | ||
293 | return 1; | ||
294 | } | ||
295 | } | ||
296 | } | ||
297 | |||
298 | /*chan is not in the region table */ | ||
299 | LEAVE(); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | /** | ||
304 | * @brief This function checks if chan txpwr is learned from AP/IBSS | ||
305 | * @param chan chan number | ||
306 | * @param parsed_region_chan pointer to parsed_region_chan_11d | ||
307 | * @return 0 | ||
308 | */ | ||
309 | static int parse_domain_info_11d(struct ieeetypes_countryinfofullset* | ||
310 | countryinfo, | ||
311 | u8 band, | ||
312 | struct parsed_region_chan_11d * | ||
313 | parsed_region_chan) | ||
314 | { | ||
315 | u8 nr_subband, nrchan; | ||
316 | u8 lastchan, firstchan; | ||
317 | u8 region; | ||
318 | u8 curchan = 0; | ||
319 | |||
320 | u8 idx = 0; /*chan index in parsed_region_chan */ | ||
321 | |||
322 | u8 j, i; | ||
323 | |||
324 | ENTER(); | ||
325 | |||
326 | /*validation Rules: | ||
327 | 1. valid region Code | ||
328 | 2. First Chan increment | ||
329 | 3. channel range no overlap | ||
330 | 4. channel is valid? | ||
331 | 5. channel is supported by region? | ||
332 | 6. Others | ||
333 | */ | ||
334 | |||
335 | lbs_dbg_hex("CountryInfo:", (u8 *) countryinfo, 30); | ||
336 | |||
337 | if ((*(countryinfo->countrycode)) == 0 | ||
338 | || (countryinfo->len <= COUNTRY_CODE_LEN)) { | ||
339 | /* No region Info or Wrong region info: treat as No 11D info */ | ||
340 | LEAVE(); | ||
341 | return 0; | ||
342 | } | ||
343 | |||
344 | /*Step1: check region_code */ | ||
345 | parsed_region_chan->region = region = | ||
346 | wlan_region_2_code(countryinfo->countrycode); | ||
347 | |||
348 | lbs_pr_debug(1, "regioncode=%x\n", (u8) parsed_region_chan->region); | ||
349 | lbs_dbg_hex("CountryCode:", (char *)countryinfo->countrycode, | ||
350 | COUNTRY_CODE_LEN); | ||
351 | |||
352 | parsed_region_chan->band = band; | ||
353 | |||
354 | memcpy(parsed_region_chan->countrycode, countryinfo->countrycode, | ||
355 | COUNTRY_CODE_LEN); | ||
356 | |||
357 | nr_subband = (countryinfo->len - COUNTRY_CODE_LEN) / | ||
358 | sizeof(struct ieeetypes_subbandset); | ||
359 | |||
360 | for (j = 0, lastchan = 0; j < nr_subband; j++) { | ||
361 | |||
362 | if (countryinfo->subband[j].firstchan <= lastchan) { | ||
363 | /*Step2&3. Check First Chan Num increment and no overlap */ | ||
364 | lbs_pr_debug(1, "11D: Chan[%d>%d] Overlap\n", | ||
365 | countryinfo->subband[j].firstchan, lastchan); | ||
366 | continue; | ||
367 | } | ||
368 | |||
369 | firstchan = countryinfo->subband[j].firstchan; | ||
370 | nrchan = countryinfo->subband[j].nrchan; | ||
371 | |||
372 | for (i = 0; idx < MAX_NO_OF_CHAN && i < nrchan; i++) { | ||
373 | /*step4: channel is supported? */ | ||
374 | |||
375 | if (!wlan_get_chan_11d(band, firstchan, i, &curchan)) { | ||
376 | /* Chan is not found in UN table */ | ||
377 | lbs_pr_debug(1, "chan is not supported: %d \n", i); | ||
378 | break; | ||
379 | } | ||
380 | |||
381 | lastchan = curchan; | ||
382 | |||
383 | if (wlan_region_chan_supported_11d | ||
384 | (region, band, curchan)) { | ||
385 | /*step5: Check if curchan is supported by mrvl in region */ | ||
386 | parsed_region_chan->chanpwr[idx].chan = curchan; | ||
387 | parsed_region_chan->chanpwr[idx].pwr = | ||
388 | countryinfo->subband[j].maxtxpwr; | ||
389 | idx++; | ||
390 | } else { | ||
391 | /*not supported and ignore the chan */ | ||
392 | lbs_pr_debug(1, | ||
393 | "11D:i[%d] chan[%d] unsupported in region[%x] band[%d]\n", | ||
394 | i, curchan, region, band); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | /*Step6: Add other checking if any */ | ||
399 | |||
400 | } | ||
401 | |||
402 | parsed_region_chan->nr_chan = idx; | ||
403 | |||
404 | lbs_pr_debug(1, "nrchan=%x\n", parsed_region_chan->nr_chan); | ||
405 | lbs_dbg_hex("11D:parsed_region_chan:", (u8 *) parsed_region_chan, | ||
406 | 2 + COUNTRY_CODE_LEN + sizeof(struct parsed_region_chan_11d) * idx); | ||
407 | |||
408 | LEAVE(); | ||
409 | return 0; | ||
410 | } | ||
411 | |||
412 | /** | ||
413 | * @brief This function calculates the scan type for channels | ||
414 | * @param chan chan number | ||
415 | * @param parsed_region_chan pointer to parsed_region_chan_11d | ||
416 | * @return PASSIVE if chan is unknown; ACTIVE if chan is known | ||
417 | */ | ||
418 | u8 libertas_get_scan_type_11d(u8 chan, | ||
419 | struct parsed_region_chan_11d * parsed_region_chan) | ||
420 | { | ||
421 | u8 scan_type = cmd_scan_type_passive; | ||
422 | |||
423 | ENTER(); | ||
424 | |||
425 | if (wlan_channel_known_11d(chan, parsed_region_chan)) { | ||
426 | lbs_pr_debug(1, "11D: Found and do Active Scan\n"); | ||
427 | scan_type = cmd_scan_type_active; | ||
428 | } else { | ||
429 | lbs_pr_debug(1, "11D: Not Find and do Passive Scan\n"); | ||
430 | } | ||
431 | |||
432 | LEAVE(); | ||
433 | return scan_type; | ||
434 | |||
435 | } | ||
436 | |||
437 | void libertas_init_11d(wlan_private * priv) | ||
438 | { | ||
439 | priv->adapter->enable11d = 0; | ||
440 | memset(&(priv->adapter->parsed_region_chan), 0, | ||
441 | sizeof(struct parsed_region_chan_11d)); | ||
442 | return; | ||
443 | } | ||
444 | |||
445 | static int wlan_enable_11d(wlan_private * priv, u8 flag) | ||
446 | { | ||
447 | int ret; | ||
448 | |||
449 | priv->adapter->enable11d = flag; | ||
450 | |||
451 | /* send cmd to FW to enable/disable 11D function in FW */ | ||
452 | ret = libertas_prepare_and_send_command(priv, | ||
453 | cmd_802_11_snmp_mib, | ||
454 | cmd_act_set, | ||
455 | cmd_option_waitforrsp, | ||
456 | OID_802_11D_ENABLE, | ||
457 | &priv->adapter->enable11d); | ||
458 | if (ret) | ||
459 | lbs_pr_debug(1, "11D: Fail to enable 11D \n"); | ||
460 | |||
461 | return 0; | ||
462 | } | ||
463 | |||
464 | /** | ||
465 | * @brief This function sets DOMAIN INFO to FW | ||
466 | * @param priv pointer to wlan_private | ||
467 | * @return 0; -1 | ||
468 | */ | ||
469 | static int set_domain_info_11d(wlan_private * priv) | ||
470 | { | ||
471 | int ret; | ||
472 | |||
473 | if (!priv->adapter->enable11d) { | ||
474 | lbs_pr_debug(1, "11D: dnld domain Info with 11d disabled\n"); | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | ret = libertas_prepare_and_send_command(priv, cmd_802_11d_domain_info, | ||
479 | cmd_act_set, | ||
480 | cmd_option_waitforrsp, 0, NULL); | ||
481 | if (ret) | ||
482 | lbs_pr_debug(1, "11D: Fail to dnld domain Info\n"); | ||
483 | |||
484 | return ret; | ||
485 | } | ||
486 | |||
487 | /** | ||
488 | * @brief This function setups scan channels | ||
489 | * @param priv pointer to wlan_private | ||
490 | * @param band band | ||
491 | * @return 0 | ||
492 | */ | ||
493 | int libertas_set_universaltable(wlan_private * priv, u8 band) | ||
494 | { | ||
495 | wlan_adapter *adapter = priv->adapter; | ||
496 | u16 size = sizeof(struct chan_freq_power); | ||
497 | u16 i = 0; | ||
498 | |||
499 | memset(adapter->universal_channel, 0, | ||
500 | sizeof(adapter->universal_channel)); | ||
501 | |||
502 | adapter->universal_channel[i].nrcfp = | ||
503 | sizeof(channel_freq_power_UN_BG) / size; | ||
504 | lbs_pr_debug(1, "11D: BG-band nrcfp=%d\n", | ||
505 | adapter->universal_channel[i].nrcfp); | ||
506 | |||
507 | adapter->universal_channel[i].CFP = channel_freq_power_UN_BG; | ||
508 | adapter->universal_channel[i].valid = 1; | ||
509 | adapter->universal_channel[i].region = UNIVERSAL_REGION_CODE; | ||
510 | adapter->universal_channel[i].band = band; | ||
511 | i++; | ||
512 | |||
513 | return 0; | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * @brief This function implements command CMD_802_11D_DOMAIN_INFO | ||
518 | * @param priv pointer to wlan_private | ||
519 | * @param cmd pointer to cmd buffer | ||
520 | * @param cmdno cmd ID | ||
521 | * @param cmdOption cmd action | ||
522 | * @return 0 | ||
523 | */ | ||
524 | int libertas_cmd_802_11d_domain_info(wlan_private * priv, | ||
525 | struct cmd_ds_command *cmd, u16 cmdno, | ||
526 | u16 cmdoption) | ||
527 | { | ||
528 | struct cmd_ds_802_11d_domain_info *pdomaininfo = | ||
529 | &cmd->params.domaininfo; | ||
530 | struct mrvlietypes_domainparamset *domain = &pdomaininfo->domain; | ||
531 | wlan_adapter *adapter = priv->adapter; | ||
532 | u8 nr_subband = adapter->domainreg.nr_subband; | ||
533 | |||
534 | ENTER(); | ||
535 | |||
536 | lbs_pr_debug(1, "nr_subband=%x\n", nr_subband); | ||
537 | |||
538 | cmd->command = cpu_to_le16(cmdno); | ||
539 | pdomaininfo->action = cpu_to_le16(cmdoption); | ||
540 | if (cmdoption == cmd_act_get) { | ||
541 | cmd->size = | ||
542 | cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); | ||
543 | lbs_dbg_hex("11D: 802_11D_DOMAIN_INFO:", (u8 *) cmd, | ||
544 | (int)(cmd->size)); | ||
545 | LEAVE(); | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); | ||
550 | memcpy(domain->countrycode, adapter->domainreg.countrycode, | ||
551 | sizeof(domain->countrycode)); | ||
552 | |||
553 | domain->header.len = | ||
554 | cpu_to_le16(nr_subband * sizeof(struct ieeetypes_subbandset) + | ||
555 | sizeof(domain->countrycode)); | ||
556 | |||
557 | if (nr_subband) { | ||
558 | memcpy(domain->subband, adapter->domainreg.subband, | ||
559 | nr_subband * sizeof(struct ieeetypes_subbandset)); | ||
560 | |||
561 | cmd->size = cpu_to_le16(sizeof(pdomaininfo->action) + | ||
562 | domain->header.len + | ||
563 | sizeof(struct mrvlietypesheader) + | ||
564 | S_DS_GEN); | ||
565 | } else { | ||
566 | cmd->size = | ||
567 | cpu_to_le16(sizeof(pdomaininfo->action) + S_DS_GEN); | ||
568 | } | ||
569 | |||
570 | lbs_dbg_hex("11D:802_11D_DOMAIN_INFO:", (u8 *) cmd, (int)(cmd->size)); | ||
571 | |||
572 | LEAVE(); | ||
573 | |||
574 | return 0; | ||
575 | } | ||
576 | |||
577 | /** | ||
578 | * @brief This function implements private cmd: enable/disable 11D | ||
579 | * @param priv pointer to wlan_private | ||
580 | * @param wrq pointer to user data | ||
581 | * @return 0 or -1 | ||
582 | */ | ||
583 | int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq) | ||
584 | { | ||
585 | int data = 0; | ||
586 | int *val; | ||
587 | |||
588 | ENTER(); | ||
589 | data = SUBCMD_DATA(wrq); | ||
590 | |||
591 | lbs_pr_debug(1, "enable 11D: %s\n", | ||
592 | (data == 1) ? "enable" : "Disable"); | ||
593 | |||
594 | wlan_enable_11d(priv, data); | ||
595 | val = (int *)wrq->u.name; | ||
596 | *val = priv->adapter->enable11d; | ||
597 | |||
598 | LEAVE(); | ||
599 | return 0; | ||
600 | } | ||
601 | |||
602 | /** | ||
603 | * @brief This function parses countryinfo from AP and download country info to FW | ||
604 | * @param priv pointer to wlan_private | ||
605 | * @param resp pointer to command response buffer | ||
606 | * @return 0; -1 | ||
607 | */ | ||
608 | int libertas_ret_802_11d_domain_info(wlan_private * priv, | ||
609 | struct cmd_ds_command *resp) | ||
610 | { | ||
611 | struct cmd_ds_802_11d_domain_info | ||
612 | *domaininfo = &resp->params.domaininforesp; | ||
613 | struct mrvlietypes_domainparamset *domain = &domaininfo->domain; | ||
614 | u16 action = le16_to_cpu(domaininfo->action); | ||
615 | s16 ret = 0; | ||
616 | u8 nr_subband = 0; | ||
617 | |||
618 | ENTER(); | ||
619 | |||
620 | lbs_dbg_hex("11D DOMAIN Info Rsp Data:", (u8 *) resp, | ||
621 | (int)le16_to_cpu(resp->size)); | ||
622 | |||
623 | nr_subband = (domain->header.len - 3) / sizeof(struct ieeetypes_subbandset); | ||
624 | /* countrycode 3 bytes */ | ||
625 | |||
626 | lbs_pr_debug(1, "11D Domain Info Resp: nr_subband=%d\n", nr_subband); | ||
627 | |||
628 | if (nr_subband > MRVDRV_MAX_SUBBAND_802_11D) { | ||
629 | lbs_pr_debug(1, "Invalid Numrer of Subband returned!!\n"); | ||
630 | return -1; | ||
631 | } | ||
632 | |||
633 | switch (action) { | ||
634 | case cmd_act_set: /*Proc Set action */ | ||
635 | break; | ||
636 | |||
637 | case cmd_act_get: | ||
638 | break; | ||
639 | default: | ||
640 | lbs_pr_debug(1, "Invalid action:%d\n", domaininfo->action); | ||
641 | ret = -1; | ||
642 | break; | ||
643 | } | ||
644 | |||
645 | LEAVE(); | ||
646 | return ret; | ||
647 | } | ||
648 | |||
649 | /** | ||
650 | * @brief This function parses countryinfo from AP and download country info to FW | ||
651 | * @param priv pointer to wlan_private | ||
652 | * @return 0; -1 | ||
653 | */ | ||
654 | int libertas_parse_dnld_countryinfo_11d(wlan_private * priv) | ||
655 | { | ||
656 | int ret; | ||
657 | wlan_adapter *adapter = priv->adapter; | ||
658 | |||
659 | ENTER(); | ||
660 | if (priv->adapter->enable11d) { | ||
661 | memset(&adapter->parsed_region_chan, 0, | ||
662 | sizeof(struct parsed_region_chan_11d)); | ||
663 | ret = parse_domain_info_11d(&adapter->pattemptedbssdesc-> | ||
664 | countryinfo, 0, | ||
665 | &adapter->parsed_region_chan); | ||
666 | |||
667 | if (ret == -1) { | ||
668 | lbs_pr_debug(1, "11D: Err Parse domain_info from AP..\n"); | ||
669 | LEAVE(); | ||
670 | return ret; | ||
671 | } | ||
672 | |||
673 | memset(&adapter->domainreg, 0, | ||
674 | sizeof(struct wlan_802_11d_domain_reg)); | ||
675 | generate_domain_info_11d(&adapter->parsed_region_chan, | ||
676 | &adapter->domainreg); | ||
677 | |||
678 | ret = set_domain_info_11d(priv); | ||
679 | |||
680 | if (ret) { | ||
681 | lbs_pr_debug(1, "11D: Err set domainInfo to FW\n"); | ||
682 | LEAVE(); | ||
683 | return ret; | ||
684 | } | ||
685 | } | ||
686 | LEAVE(); | ||
687 | return 0; | ||
688 | } | ||
689 | |||
690 | /** | ||
691 | * @brief This function generates 11D info from user specified regioncode and download to FW | ||
692 | * @param priv pointer to wlan_private | ||
693 | * @return 0; -1 | ||
694 | */ | ||
695 | int libertas_create_dnld_countryinfo_11d(wlan_private * priv) | ||
696 | { | ||
697 | int ret; | ||
698 | wlan_adapter *adapter = priv->adapter; | ||
699 | struct region_channel *region_chan; | ||
700 | u8 j; | ||
701 | |||
702 | ENTER(); | ||
703 | lbs_pr_debug(1, "11D:curbssparams.band[%d]\n", adapter->curbssparams.band); | ||
704 | |||
705 | if (priv->adapter->enable11d) { | ||
706 | /* update parsed_region_chan_11; dnld domaininf to FW */ | ||
707 | |||
708 | for (j = 0; j < sizeof(adapter->region_channel) / | ||
709 | sizeof(adapter->region_channel[0]); j++) { | ||
710 | region_chan = &adapter->region_channel[j]; | ||
711 | |||
712 | lbs_pr_debug(1, "11D:[%d] region_chan->band[%d]\n", j, | ||
713 | region_chan->band); | ||
714 | |||
715 | if (!region_chan || !region_chan->valid | ||
716 | || !region_chan->CFP) | ||
717 | continue; | ||
718 | if (region_chan->band != adapter->curbssparams.band) | ||
719 | continue; | ||
720 | break; | ||
721 | } | ||
722 | |||
723 | if (j >= sizeof(adapter->region_channel) / | ||
724 | sizeof(adapter->region_channel[0])) { | ||
725 | lbs_pr_debug(1, "11D:region_chan not found. band[%d]\n", | ||
726 | adapter->curbssparams.band); | ||
727 | LEAVE(); | ||
728 | return -1; | ||
729 | } | ||
730 | |||
731 | memset(&adapter->parsed_region_chan, 0, | ||
732 | sizeof(struct parsed_region_chan_11d)); | ||
733 | wlan_generate_parsed_region_chan_11d(region_chan, | ||
734 | &adapter-> | ||
735 | parsed_region_chan); | ||
736 | |||
737 | memset(&adapter->domainreg, 0, | ||
738 | sizeof(struct wlan_802_11d_domain_reg)); | ||
739 | generate_domain_info_11d(&adapter->parsed_region_chan, | ||
740 | &adapter->domainreg); | ||
741 | |||
742 | ret = set_domain_info_11d(priv); | ||
743 | |||
744 | if (ret) { | ||
745 | lbs_pr_debug(1, "11D: Err set domainInfo to FW\n"); | ||
746 | LEAVE(); | ||
747 | return ret; | ||
748 | } | ||
749 | |||
750 | } | ||
751 | |||
752 | LEAVE(); | ||
753 | return 0; | ||
754 | } | ||
diff --git a/drivers/net/wireless/libertas/11d.h b/drivers/net/wireless/libertas/11d.h new file mode 100644 index 000000000000..db2ebea9f231 --- /dev/null +++ b/drivers/net/wireless/libertas/11d.h | |||
@@ -0,0 +1,105 @@ | |||
1 | /** | ||
2 | * This header file contains data structures and | ||
3 | * function declarations of 802.11d | ||
4 | */ | ||
5 | #ifndef _WLAN_11D_ | ||
6 | #define _WLAN_11D_ | ||
7 | |||
8 | #include "types.h" | ||
9 | #include "defs.h" | ||
10 | |||
11 | #define UNIVERSAL_REGION_CODE 0xff | ||
12 | |||
13 | /** (Beaconsize(256)-5(IEId,len,contrystr(3))/3(FirstChan,NoOfChan,MaxPwr) | ||
14 | */ | ||
15 | #define MRVDRV_MAX_SUBBAND_802_11D 83 | ||
16 | |||
17 | #define COUNTRY_CODE_LEN 3 | ||
18 | #define MAX_NO_OF_CHAN 40 | ||
19 | |||
20 | struct cmd_ds_command; | ||
21 | |||
22 | /** Data structure for Country IE*/ | ||
23 | struct ieeetypes_subbandset { | ||
24 | u8 firstchan; | ||
25 | u8 nrchan; | ||
26 | u8 maxtxpwr; | ||
27 | } __attribute__ ((packed)); | ||
28 | |||
29 | struct ieeetypes_countryinfoset { | ||
30 | u8 element_id; | ||
31 | u8 len; | ||
32 | u8 countrycode[COUNTRY_CODE_LEN]; | ||
33 | struct ieeetypes_subbandset subband[1]; | ||
34 | }; | ||
35 | |||
36 | struct ieeetypes_countryinfofullset { | ||
37 | u8 element_id; | ||
38 | u8 len; | ||
39 | u8 countrycode[COUNTRY_CODE_LEN]; | ||
40 | struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; | ||
41 | } __attribute__ ((packed)); | ||
42 | |||
43 | struct mrvlietypes_domainparamset { | ||
44 | struct mrvlietypesheader header; | ||
45 | u8 countrycode[COUNTRY_CODE_LEN]; | ||
46 | struct ieeetypes_subbandset subband[1]; | ||
47 | } __attribute__ ((packed)); | ||
48 | |||
49 | struct cmd_ds_802_11d_domain_info { | ||
50 | u16 action; | ||
51 | struct mrvlietypes_domainparamset domain; | ||
52 | } __attribute__ ((packed)); | ||
53 | |||
54 | /** domain regulatory information */ | ||
55 | struct wlan_802_11d_domain_reg { | ||
56 | /** country Code*/ | ||
57 | u8 countrycode[COUNTRY_CODE_LEN]; | ||
58 | /** No. of subband*/ | ||
59 | u8 nr_subband; | ||
60 | struct ieeetypes_subbandset subband[MRVDRV_MAX_SUBBAND_802_11D]; | ||
61 | }; | ||
62 | |||
63 | struct chan_power_11d { | ||
64 | u8 chan; | ||
65 | u8 pwr; | ||
66 | } __attribute__ ((packed)); | ||
67 | |||
68 | struct parsed_region_chan_11d { | ||
69 | u8 band; | ||
70 | u8 region; | ||
71 | s8 countrycode[COUNTRY_CODE_LEN]; | ||
72 | struct chan_power_11d chanpwr[MAX_NO_OF_CHAN]; | ||
73 | u8 nr_chan; | ||
74 | } __attribute__ ((packed)); | ||
75 | |||
76 | struct region_code_mapping { | ||
77 | u8 region[COUNTRY_CODE_LEN]; | ||
78 | u8 code; | ||
79 | }; | ||
80 | |||
81 | u8 libertas_get_scan_type_11d(u8 chan, | ||
82 | struct parsed_region_chan_11d *parsed_region_chan); | ||
83 | |||
84 | u32 libertas_chan_2_freq(u8 chan, u8 band); | ||
85 | |||
86 | enum state_11d libertas_get_state_11d(wlan_private * priv); | ||
87 | |||
88 | void libertas_init_11d(wlan_private * priv); | ||
89 | |||
90 | int libertas_set_universaltable(wlan_private * priv, u8 band); | ||
91 | |||
92 | int libertas_cmd_802_11d_domain_info(wlan_private * priv, | ||
93 | struct cmd_ds_command *cmd, u16 cmdno, | ||
94 | u16 cmdOption); | ||
95 | |||
96 | int libertas_cmd_enable_11d(wlan_private * priv, struct iwreq *wrq); | ||
97 | |||
98 | int libertas_ret_802_11d_domain_info(wlan_private * priv, | ||
99 | struct cmd_ds_command *resp); | ||
100 | |||
101 | int libertas_parse_dnld_countryinfo_11d(wlan_private * priv); | ||
102 | |||
103 | int libertas_create_dnld_countryinfo_11d(wlan_private * priv); | ||
104 | |||
105 | #endif /* _WLAN_11D_ */ | ||
diff --git a/drivers/net/wireless/libertas/LICENSE b/drivers/net/wireless/libertas/LICENSE new file mode 100644 index 000000000000..8862742213b9 --- /dev/null +++ b/drivers/net/wireless/libertas/LICENSE | |||
@@ -0,0 +1,16 @@ | |||
1 | Copyright (c) 2003-2006, Marvell International Ltd. | ||
2 | All Rights Reserved | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify it | ||
5 | under the terms of version 2 of the GNU General Public License as | ||
6 | published by the Free Software Foundation. | ||
7 | |||
8 | This program is distributed in the hope that it will be useful, but WITHOUT | ||
9 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | more details. | ||
12 | |||
13 | You should have received a copy of the GNU General Public License along with | ||
14 | this program; if not, write to the Free Software Foundation, Inc., 59 | ||
15 | Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
16 | |||
diff --git a/drivers/net/wireless/libertas/Makefile b/drivers/net/wireless/libertas/Makefile new file mode 100644 index 000000000000..19c935071d8e --- /dev/null +++ b/drivers/net/wireless/libertas/Makefile | |||
@@ -0,0 +1,21 @@ | |||
1 | # EXTRA_CFLAGS += -Wpacked | ||
2 | |||
3 | usb8xxx-objs := main.o fw.o wext.o \ | ||
4 | rx.o tx.o cmd.o \ | ||
5 | cmdresp.o scan.o \ | ||
6 | join.o 11d.o \ | ||
7 | ioctl.o debugfs.o \ | ||
8 | ethtool.o assoc.o | ||
9 | |||
10 | ifeq ($(CONFIG_LIBERTAS_USB_DEBUG), y) | ||
11 | EXTRA_CFLAGS += -DDEBUG -DPROC_DEBUG | ||
12 | endif | ||
13 | |||
14 | |||
15 | # This is needed to support the newer boot2 bootloader (v >= 3104) | ||
16 | EXTRA_CFLAGS += -DSUPPORT_BOOT_COMMAND | ||
17 | usb8xxx-objs += if_bootcmd.o | ||
18 | usb8xxx-objs += if_usb.o | ||
19 | |||
20 | obj-$(CONFIG_LIBERTAS_USB) += usb8xxx.o | ||
21 | |||
diff --git a/drivers/net/wireless/libertas/README b/drivers/net/wireless/libertas/README new file mode 100644 index 000000000000..688da4c784b1 --- /dev/null +++ b/drivers/net/wireless/libertas/README | |||
@@ -0,0 +1,1044 @@ | |||
1 | ================================================================================ | ||
2 | README for USB8388 | ||
3 | |||
4 | (c) Copyright © 2003-2006, Marvell International Ltd. | ||
5 | All Rights Reserved | ||
6 | |||
7 | This software file (the "File") is distributed by Marvell International | ||
8 | Ltd. under the terms of the GNU General Public License Version 2, June 1991 | ||
9 | (the "License"). You may use, redistribute and/or modify this File in | ||
10 | accordance with the terms and conditions of the License, a copy of which | ||
11 | is available along with the File in the license.txt file or by writing to | ||
12 | the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||
13 | 02111-1307 or on the worldwide web at http://www.gnu.org/licenses/gpl.txt. | ||
14 | |||
15 | THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE | ||
16 | IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE | ||
17 | ARE EXPRESSLY DISCLAIMED. The License provides additional details about | ||
18 | this warranty disclaimer. | ||
19 | ================================================================================ | ||
20 | |||
21 | ===================== | ||
22 | DRIVER LOADING | ||
23 | ===================== | ||
24 | |||
25 | o. Copy the firmware image (e.g. usb8388.bin) to /lib/firmware/ | ||
26 | |||
27 | o. Load driver by using the following command: | ||
28 | |||
29 | insmod usb8388.ko [fw_name=usb8388.bin] | ||
30 | |||
31 | ===================== | ||
32 | IWPRIV COMMAND | ||
33 | ===================== | ||
34 | |||
35 | NAME | ||
36 | This manual describes the usage of private commands used in Marvell WLAN | ||
37 | Linux Driver. All the commands available in Wlanconfig will not be available | ||
38 | in the iwpriv. | ||
39 | |||
40 | SYNOPSIS | ||
41 | iwpriv <ethX> <command> [sub-command] ... | ||
42 | |||
43 | iwpriv ethX version | ||
44 | iwpriv ethX scantype [sub-command] | ||
45 | iwpriv ethX getSNR <n> | ||
46 | iwpriv ethX getNF <n> | ||
47 | iwpriv ethX getRSSI <n> | ||
48 | iwpriv ethX setrxant <n> | ||
49 | iwpriv ethX getrxant | ||
50 | iwpriv ethX settxant <n> | ||
51 | iwpriv ethX gettxant | ||
52 | iwpriv ethX authalgs <n> | ||
53 | iwpriv ethX pre-TBTT <n> | ||
54 | iwpriv ethX 8021xauthalgs <n> | ||
55 | iwpriv ethX encryptionmode <n> | ||
56 | iwpriv ethX setregioncode <n> | ||
57 | iwpriv ethX getregioncode | ||
58 | iwpriv ethX setbcnavg <n> | ||
59 | iwpriv ethX getbcnavg | ||
60 | iwpriv ethX setdataavg <n> | ||
61 | iwpriv ethX setlisteninter <n> | ||
62 | iwpriv ethX getlisteninter | ||
63 | iwpriv ethX setmultipledtim <n> | ||
64 | iwpriv ethX getmultipledtim | ||
65 | iwpriv ethX atimwindow <n> | ||
66 | iwpriv ethX deauth | ||
67 | iwpriv ethX adhocstop | ||
68 | iwpriv ethX radioon | ||
69 | iwpriv ethX radiooff | ||
70 | iwpriv ethX reasso-on | ||
71 | iwpriv ethX reasso-off | ||
72 | iwpriv ethX scanmode [sub-command] | ||
73 | iwpriv ethX setwpaie <n> | ||
74 | iwpriv ethX wlanidle-off | ||
75 | iwpriv ethX wlanidle-on | ||
76 | iwpriv ethX getcis | ||
77 | iwpriv ethX getlog | ||
78 | iwpriv ethX getadhocstatus | ||
79 | iwpriv ethX adhocgrate <n> | ||
80 | |||
81 | Version 4 Command: | ||
82 | iwpriv ethX inactvityto <n> | ||
83 | iwpriv ethX sleeppd <n> | ||
84 | iwpriv ethX enable11d <n> | ||
85 | iwpriv ethX tpccfg <n> | ||
86 | iwpriv ethX powercfg <n> | ||
87 | iwpriv ethX setafc <n> | ||
88 | iwpriv ethX getafc | ||
89 | |||
90 | Version 5 Command: | ||
91 | iwpriv ethX ledgpio <n> | ||
92 | iwpriv ethX scanprobes <n> | ||
93 | iwpriv ethX lolisteninter <n> | ||
94 | iwpriv ethX rateadapt <n> <m> | ||
95 | iwpriv ethX txcontrol <n> | ||
96 | iwpriv ethX psnullinterval <n> | ||
97 | iwpriv ethX prescan <n> | ||
98 | iwpriv ethX getrxinfo | ||
99 | iwpriv ethX gettxrate | ||
100 | iwpriv ethX beaconinterval | ||
101 | |||
102 | BT Commands: | ||
103 | The blinding table (BT) contains a list of mac addresses that should be | ||
104 | ignored by the firmware. It is primarily used for debugging and | ||
105 | testing networks. It can be edited and inspected with the following | ||
106 | commands: | ||
107 | |||
108 | iwpriv ethX bt_reset | ||
109 | iwpriv ethX bt_add <mac_address> | ||
110 | iwpriv ethX bt_del <mac_address> | ||
111 | iwpriv ethX bt_list <id> | ||
112 | |||
113 | FWT Commands: | ||
114 | The forwarding table (FWT) is a feature used to manage mesh network | ||
115 | routing in the firmware. The FWT is essentially a routing table that | ||
116 | associates a destination mac address (da) with a next hop receiver | ||
117 | address (ra). The FWT can be inspected and edited with the following | ||
118 | iwpriv commands, which are described in greater detail below. | ||
119 | Eventually, the table will be automatically maintained by a custom | ||
120 | routing protocol. | ||
121 | |||
122 | NOTE: FWT commands replace the previous DFT commands. What were the DFT | ||
123 | commands?, you might ask. They were an earlier API to the firmware that | ||
124 | implemented a simple MAC-layer forwarding mechanism. In the unlikely | ||
125 | event that you were using these commands, you must migrate to the new | ||
126 | FWT commands which can be used to achieve the same functionality. | ||
127 | |||
128 | iwpriv ethX fwt_add [parameters] | ||
129 | iwpriv ethX fwt_del [parameters] | ||
130 | iwpriv ethX fwt_lookup [parameters] | ||
131 | iwpriv ethX fwt_list [parameters] | ||
132 | iwpriv ethX fwt_list_route [parameters] | ||
133 | iwpriv ethX fwt_list_neigh [parameters] | ||
134 | iwpriv ethX fwt_reset [parameters] | ||
135 | iwpriv ethX fwt_cleanup | ||
136 | iwpriv ethX fwt_time | ||
137 | |||
138 | MESH Commands: | ||
139 | |||
140 | The MESH commands are used to configure various features of the mesh | ||
141 | routing protocol. The following commands are supported: | ||
142 | |||
143 | iwpriv ethX mesh_get_ttl | ||
144 | iwpriv ethX mesh_set_ttl ttl | ||
145 | |||
146 | DESCRIPTION | ||
147 | Those commands are used to send additional commands to the Marvell WLAN | ||
148 | card via the Linux device driver. | ||
149 | |||
150 | The ethX parameter specifies the network device that is to be used to | ||
151 | perform this command on. it could be eth0, eth1 etc. | ||
152 | |||
153 | version | ||
154 | This is used to get the current version of the driver and the firmware. | ||
155 | |||
156 | scantype | ||
157 | This command is used to set the scan type to be used by the driver in | ||
158 | the scan command. This setting will not be used while performing a scan | ||
159 | for a specific SSID, as it is always done with scan type being active. | ||
160 | |||
161 | where the sub-commands are: - | ||
162 | active -- to set the scan type to active | ||
163 | passive -- to set the scan type to passive | ||
164 | get -- to get the scan type set in the driver | ||
165 | |||
166 | getSNR | ||
167 | This command gets the average and non average value of Signal to Noise | ||
168 | Ratio of Beacon and Data. | ||
169 | |||
170 | where value is:- | ||
171 | 0 -- Beacon non-average. | ||
172 | 1 -- Beacon average. | ||
173 | 2 -- Data non-average. | ||
174 | 3 -- Data average. | ||
175 | |||
176 | If no value is given, all four values are returned in the order mentioned | ||
177 | above. | ||
178 | |||
179 | Note: This command is available only when STA is connected. | ||
180 | |||
181 | getRSSI | ||
182 | This command gets the average and non average value os Receive Signal | ||
183 | Strength of Beacon and Data. | ||
184 | |||
185 | where value is:- | ||
186 | 0 -- Beacon non-average. | ||
187 | 1 -- Beacon average. | ||
188 | 2 -- Data non-average. | ||
189 | 3 -- Data average. | ||
190 | |||
191 | Note: This command is available only when STA is connected. | ||
192 | |||
193 | getNF | ||
194 | This command gets the average and non average value of Noise Floor of | ||
195 | Beacon and Data. | ||
196 | |||
197 | where value is:- | ||
198 | 0 -- Beacon non-average. | ||
199 | 1 -- Beacon average. | ||
200 | 2 -- Data non-average. | ||
201 | 3 -- Data average. | ||
202 | |||
203 | Note: This command is available only when STA is connected. | ||
204 | |||
205 | setrxant | ||
206 | This command is used to set the mode for Rx antenna. | ||
207 | |||
208 | The options that can be sent are:- | ||
209 | 1 -- Antenna 1. | ||
210 | 2 -- Antenna 2. | ||
211 | 0xFFFF -- Diversity. | ||
212 | |||
213 | Usage: | ||
214 | iwpriv ethX setrxant 0x01: select Antenna 1. | ||
215 | |||
216 | getrxant | ||
217 | This command is used to get the mode for Rx antenna. | ||
218 | |||
219 | |||
220 | settxant | ||
221 | This command is used to set the mode for Tx antenna. | ||
222 | The options that can be sent are:- | ||
223 | 1 -- Antenna 1. | ||
224 | 2 -- Antenna 2. | ||
225 | 0xFFFF -- Diversity. | ||
226 | Usage: | ||
227 | iwpriv ethX settxant 0x01: select Antenna 1. | ||
228 | |||
229 | gettxant | ||
230 | This command is used to get the mode for Tx antenna. | ||
231 | |||
232 | authalgs | ||
233 | This command is used by the WPA supplicant to set the authentication | ||
234 | algorithms in the station. | ||
235 | |||
236 | 8021xauthalgs | ||
237 | This command is used by the WPA supplicant to set the 8021.x authentication algorithm type | ||
238 | station. | ||
239 | |||
240 | where values can be:- | ||
241 | 1 -- None | ||
242 | 2 -- LEAP | ||
243 | 4 -- TLS | ||
244 | 8 -- TTLs | ||
245 | 16 -- MD5 | ||
246 | |||
247 | |||
248 | encryptionmode | ||
249 | This command is used by the WPA supplicant to set the encryption algorithm. | ||
250 | |||
251 | where values can be:- | ||
252 | 0 -- NONE | ||
253 | 1 -- WEP40 | ||
254 | 2 -- TKIP | ||
255 | 3 -- CCMP | ||
256 | 4 -- WEP104 | ||
257 | |||
258 | pre-TBTT | ||
259 | This command is used to set pre-TBTT time period where value is in microseconds. | ||
260 | |||
261 | setregioncode | ||
262 | This command is used to set the region code in the station. | ||
263 | where value is 'region code' for various regions like | ||
264 | USA FCC, Canada IC, Spain, France, Europe ETSI, Japan ... | ||
265 | |||
266 | Usage: | ||
267 | iwpriv ethX setregioncode 0x10: set region code to USA (0x10). | ||
268 | |||
269 | getregioncode | ||
270 | This command is used to get the region code information set in the | ||
271 | station. | ||
272 | |||
273 | setbcnavg | ||
274 | Set the weighting factor for calculating RSSI. | ||
275 | |||
276 | getbcnavg | ||
277 | Get weighting factor for calculating RSSI. | ||
278 | |||
279 | setdataavg | ||
280 | Set the weighting factor for calculating SNR. | ||
281 | |||
282 | setlisteninter | ||
283 | This command is used to set the listen interval in the | ||
284 | station. | ||
285 | |||
286 | where the value ranges between 1 - 255 | ||
287 | |||
288 | getlisteninter | ||
289 | This command is used to get the listen interval value set in the | ||
290 | station. | ||
291 | |||
292 | setmultipledtim | ||
293 | This command is used to set the multiple dtim value in the | ||
294 | station. | ||
295 | where the value is 1,2,3,4,5,0xfffe | ||
296 | 0xfffe means the firmware will use listen interval in association | ||
297 | command for waking up | ||
298 | |||
299 | getmultipledtim | ||
300 | This command is used to get the multiple dtim value set in the station. | ||
301 | |||
302 | atimwindow | ||
303 | This command is used to set the atim value in the | ||
304 | station. | ||
305 | |||
306 | where the value ranges between 0 - 50 | ||
307 | |||
308 | deauth | ||
309 | This command is used to send the de-authentication to the AP with which | ||
310 | the station is associated. This command is valid only when | ||
311 | station is in Infrastructure mode. | ||
312 | |||
313 | Note: This command is available only when STA is connected. | ||
314 | |||
315 | adhocstop | ||
316 | This command is used to stop beacon transmission from the station and | ||
317 | go into idle state in ad-hoc mode. | ||
318 | |||
319 | Note: This command is available only when STA is connected. | ||
320 | |||
321 | radioon | ||
322 | This command is used to turn on the RF antenna. | ||
323 | |||
324 | radiooff | ||
325 | This command is sued to turn off the RF antenna. | ||
326 | |||
327 | scanmode | ||
328 | This command is used to set the station to scan for either IBSS | ||
329 | networks or BSS networks or both BSS and IBSS networks. This | ||
330 | command can be used with sub commands, | ||
331 | |||
332 | where the value for | ||
333 | bss -- Scan All the BSS networks. | ||
334 | ibss -- Scan All the IBSS networks. | ||
335 | any -- Scan both BSS and IBSS networks. | ||
336 | |||
337 | |||
338 | |||
339 | setwpaie | ||
340 | This command is used by WPA supplicant to send the WPA-IE to the driver. | ||
341 | |||
342 | wlanidle-off | ||
343 | This command is used to get into idle state. | ||
344 | |||
345 | Note: This command is available only when STA is connected. | ||
346 | |||
347 | wlanidle-on | ||
348 | This command is used to get off the idle state. | ||
349 | |||
350 | Note: This command is available only when STA is connected. | ||
351 | |||
352 | |||
353 | getlog | ||
354 | This command is used to get the 802.11 statistics available in the | ||
355 | station. | ||
356 | |||
357 | Note: This command is available only when STA is connected. | ||
358 | |||
359 | getadhocstatus | ||
360 | This command is used to get the ad-hoc Network Status. | ||
361 | |||
362 | The various status codes are: | ||
363 | AdhocStarted | ||
364 | AdhocJoined | ||
365 | AdhocIdle | ||
366 | InfraMode | ||
367 | AutoUnknownMode | ||
368 | |||
369 | Note: This command is available only when STA is connected. | ||
370 | |||
371 | adhocgrate | ||
372 | This command is used to enable(1) g_rate, Disable(0) g_rate | ||
373 | and request(2) the status which g_rate is disabled/enabled, | ||
374 | for Ad-hoc creator. | ||
375 | |||
376 | where value is:- | ||
377 | 0 -- Disabled | ||
378 | 1 -- Enabled | ||
379 | 2 -- Get | ||
380 | |||
381 | ledgpio | ||
382 | This command is used to set/get LEDs. | ||
383 | |||
384 | iwpriv ethX ledgpio <LEDs> | ||
385 | will set the corresponding LED for the GPIO Line. | ||
386 | |||
387 | iwpriv ethX ledgpio | ||
388 | will give u which LEDs are Enabled. | ||
389 | |||
390 | Usage: | ||
391 | iwpriv eth1 ledgpio 1 0 2 1 3 4 | ||
392 | will enable | ||
393 | LED 1 -> GPIO 0 | ||
394 | LED 2 -> GPIO 1 | ||
395 | LED 3 -> GPIO 4 | ||
396 | |||
397 | iwpriv eth1 ledgpio | ||
398 | shows LED information in the format as mentioned above. | ||
399 | |||
400 | Note: LED0 is invalid | ||
401 | Note: Maximum Number of LEDs are 16. | ||
402 | |||
403 | inactivityto | ||
404 | This command is used by the host to set/get the inactivity timeout value, | ||
405 | which specifies when WLAN device is put to sleep. | ||
406 | |||
407 | Usage: | ||
408 | iwpriv ethX inactivityto [<timeout>] | ||
409 | |||
410 | where the parameter are: | ||
411 | timeout: timeout value in milliseconds. | ||
412 | |||
413 | Example: | ||
414 | iwpriv eth1 inactivityto | ||
415 | "get the timeout value" | ||
416 | |||
417 | iwpriv eth1 inactivityto X | ||
418 | "set timeout value to X ms" | ||
419 | |||
420 | |||
421 | sleeppd | ||
422 | This command is used to configure the sleep period of the WLAN device. | ||
423 | |||
424 | Usage: | ||
425 | iwpriv ethX sleeppd [<sleep period>] | ||
426 | |||
427 | where the parameter are: | ||
428 | Period: sleep period in milliseconds. Range 10~60. | ||
429 | |||
430 | Example: | ||
431 | iwpriv eth1 sleeppd 10 | ||
432 | "set period as 10 ms" | ||
433 | iwpriv eth1 sleeppd | ||
434 | "get the sleep period configuration" | ||
435 | |||
436 | enable11d | ||
437 | This command is used to control 11d | ||
438 | where value is:- | ||
439 | 1 -- Enabled | ||
440 | 0 -- Disabled | ||
441 | 2 -- Get | ||
442 | |||
443 | |||
444 | |||
445 | |||
446 | tpccfg | ||
447 | Enables or disables automatic transmit power control. | ||
448 | |||
449 | The first parameter turns this feature on (1) or off (0). When turning | ||
450 | on, the user must also supply four more parameters in the following | ||
451 | order: | ||
452 | -UseSNR (Use SNR (in addition to PER) for TPC algorithm), | ||
453 | -P0 (P0 power level for TPC), | ||
454 | -P1 (P1 power level for TPC), | ||
455 | -P2 (P2 power level for TPC). | ||
456 | |||
457 | Usage: | ||
458 | iwpriv ethX tpccfg: Get current configuration | ||
459 | iwpriv ethX tpccfg 0: disable auto TPC | ||
460 | iwpriv ethX tpccfg 0x01 0x00 0x05 0x0a 0x0d: enable auto TPC; do not use SNR; | ||
461 | P0=0x05; P1=0x0a; P2=0x0d; | ||
462 | iwpriv ethX tpccfg 0x01 0x01 0x05 0x0a 0x0d: enable auto TPC; use SNR; | ||
463 | P0=0x05; P1=0x0a; P2=0x0d. | ||
464 | |||
465 | powercfg | ||
466 | Enables or disables power adaptation. | ||
467 | |||
468 | The first parameter turns this feature on (1) or off (0). When turning | ||
469 | on, the user must also supply three more parameters in the following | ||
470 | order: | ||
471 | -P0 (P0 power level for Power Adaptation), | ||
472 | -P1 (P1 power level for Power Adaptation), | ||
473 | -P2 (P2 power level for Power Adaptation). | ||
474 | |||
475 | Usage: | ||
476 | iwpriv ethX powercfg: Get current configuration | ||
477 | iwpriv ethX powercfg 0: disable power adaptation | ||
478 | iwpriv ethX powercfg 1 0x0d 0x0f 0x12: enable power adaptation; | ||
479 | P0=0x0d; P1=0x0f; P2=0x12. | ||
480 | |||
481 | getafc | ||
482 | This command returns automatic frequency control parameters. It returns | ||
483 | three integers: | ||
484 | -P0: automatic is on (1), or off (0), | ||
485 | -P1: current timing offset in PPM (part per million), and | ||
486 | -P2: current frequency offset in PPM. | ||
487 | |||
488 | setafc | ||
489 | Set automatic frequency control options. | ||
490 | |||
491 | The first parameter turns automatic on (1) or off (0). | ||
492 | The user must supply two more parameters in either case, in the following | ||
493 | order: | ||
494 | |||
495 | When auto is on: | ||
496 | |||
497 | -P0 (automatic adjustment frequency threshold in PPM), | ||
498 | -P1 (automatic adjustment period in beacon period), | ||
499 | |||
500 | When auto is off: | ||
501 | |||
502 | -P0 (manual adjustment timing offset in PPM), and | ||
503 | -P1 (manual adjustment frequency offset in PPM). | ||
504 | |||
505 | Usage: | ||
506 | iwpriv ethX setafc 0 10 10: manual adjustment, both timing and frequcncy | ||
507 | offset are 10 PPM. | ||
508 | |||
509 | iwpriv ethX setafc 1 10 10 enable afc, automatic adjustment, | ||
510 | frequency threshold 10 PPM, for every 10 beacon periods. | ||
511 | |||
512 | |||
513 | |||
514 | scanprobes | ||
515 | This command sets number of probe requests per channel. | ||
516 | |||
517 | Usage: | ||
518 | iwpriv ethX scanprobes 3 (set scan probes to 3) | ||
519 | iwpriv ethX scanprobes (get scan probes) | ||
520 | |||
521 | lolisteninter | ||
522 | This command sets the value of listen interval. | ||
523 | |||
524 | Usage: | ||
525 | iwpriv ethX lolisteninter 234 (set the lolisteninter to 234) | ||
526 | iwpriv ethX lolisteninter (get the lolisteninter value) | ||
527 | |||
528 | rateadapt | ||
529 | This command sets the data rates bitmap. | ||
530 | Where <n> | ||
531 | 0: Disable auto rate adapt | ||
532 | 1: Enable auto rate adapt | ||
533 | |||
534 | <m> | ||
535 | data rate bitmap | ||
536 | Bit Data rate | ||
537 | 0 1 Mbps | ||
538 | 1 2 Mbps | ||
539 | 2 5.5 Mbps | ||
540 | 3 11 Mbps | ||
541 | 4 Reserved | ||
542 | 5 6 Mbps | ||
543 | 6 9 Mbps | ||
544 | 7 12 Mbps | ||
545 | 8 18 Mbps | ||
546 | 9 24 Mbps | ||
547 | 10 36 Mbps | ||
548 | 11 48 Mbps | ||
549 | 12 54 Mbps | ||
550 | 12-15 Reserved | ||
551 | |||
552 | Usage: | ||
553 | iwpriv ethX rateadapt | ||
554 | read the currect data rate setting | ||
555 | iwpriv ethX rateadapt 1 0x07 | ||
556 | enable auto data rate adapt and | ||
557 | data rates are 1Mbps, 2Mbsp and 5.5Mbps | ||
558 | |||
559 | |||
560 | txcontrol | ||
561 | This command is used to set the Tx rate, ack policy, and retry limit on a per packet basis. | ||
562 | |||
563 | Where value <n> is: | ||
564 | if bit[4] == 1: | ||
565 | bit[3:0] -- 0 1 2 3 4 5 6 7 8 9 10 11 12 13-16 | ||
566 | Data Rate(Mbps) -- 1 2 5.5 11 Rsv 6 9 12 18 24 36 48 54 Rsv | ||
567 | |||
568 | bit[12:8] | ||
569 | if bit[12] == 1, bit[11:8] specifies the Tx retry limit. | ||
570 | |||
571 | bit[14:13] specifies per packet ack policy: | ||
572 | bit[14:13] | ||
573 | 1 0 use immediate ack policy for this packet | ||
574 | 1 1 use no ack policy for this packet | ||
575 | 0 x use the per-packet ack policy setting | ||
576 | |||
577 | Usage: | ||
578 | iwpriv ethX txcontrol 0x7513 | ||
579 | Use no-ack policy, 5 retires for Tx, 11Mbps rate | ||
580 | |||
581 | |||
582 | |||
583 | psnullinterval | ||
584 | This command is used to set/request NULL package interval for Power Save | ||
585 | under infrastructure mode. | ||
586 | |||
587 | where value is:- | ||
588 | -1 -- Disabled | ||
589 | n>0 -- Set interval as n (seconds) | ||
590 | |||
591 | prescan | ||
592 | This command is used to enable (1)/disable(0) auto prescan before assoicate to the ap | ||
593 | |||
594 | where value is:- | ||
595 | 0 -- Disabled | ||
596 | 1 -- Enabled | ||
597 | 2 -- Get | ||
598 | |||
599 | getrxinfo | ||
600 | This command gets non average value of Signal to Noise Ratio of Data and rate index. | ||
601 | |||
602 | The following table shows RateIndex and Rate | ||
603 | |||
604 | RateIndex Data rate | ||
605 | 0 1 Mbps | ||
606 | 1 2 Mbps | ||
607 | 2 5.5 Mbps | ||
608 | 3 11 Mbps | ||
609 | 4 Reserved | ||
610 | 5 6 Mbps | ||
611 | 6 9 Mbps | ||
612 | 7 12 Mbps | ||
613 | 8 18 Mbps | ||
614 | 9 24 Mbps | ||
615 | 10 36 Mbps | ||
616 | 11 48 Mbps | ||
617 | 12 54 Mbps | ||
618 | 13-15 Reserved | ||
619 | |||
620 | gettxrate | ||
621 | This command gets current Tx rate index of the first packet associated with Rate Adaptation. | ||
622 | |||
623 | The following table shows RateIndex and Rate | ||
624 | |||
625 | RateIndex Data rate | ||
626 | 0 1 Mbps | ||
627 | 1 2 Mbps | ||
628 | 2 5.5 Mbps | ||
629 | 3 11 Mbps | ||
630 | 4 Reserved | ||
631 | 5 6 Mbps | ||
632 | 6 9 Mbps | ||
633 | 7 12 Mbps | ||
634 | 8 18 Mbps | ||
635 | 9 24 Mbps | ||
636 | 10 36 Mbps | ||
637 | 11 48 Mbps | ||
638 | 12 54 Mbps | ||
639 | 13-15 Reserved | ||
640 | |||
641 | bcninterval | ||
642 | This command is used to sets beacon interval in adhoc mode when an argument is given, and gets current adhoc | ||
643 | beacon interval when no argument is given. The valid beacon interval is between 20 - 1000, | ||
644 | default beacon interval is 100. | ||
645 | |||
646 | Usage: | ||
647 | iwpriv ethX bcninterval 100 (set adhoc beacon interval to 100) | ||
648 | iwpriv ethX bcninterval (get adhoc beacon interval) | ||
649 | |||
650 | fwt_add | ||
651 | This command is used to insert an entry into the FWT table. The list of | ||
652 | parameters must follow the following structure: | ||
653 | |||
654 | iwpriv ethX fwt_add da ra [metric dir ssn dsn hopcount ttl expiration sleepmode snr] | ||
655 | |||
656 | The parameters between brackets are optional, but they must appear in | ||
657 | the order specified. For example, if you want to specify the metric, | ||
658 | you must also specify the dir, ssn, and dsn but you need not specify the | ||
659 | hopcount, expiration, sleepmode, or snr. Any unspecified parameters | ||
660 | will be assigned the defaults specified below. | ||
661 | |||
662 | The different parameters are:- | ||
663 | da -- DA MAC address in the form 00:11:22:33:44:55 | ||
664 | ra -- RA MAC address in the form 00:11:22:33:44:55 | ||
665 | metric -- route metric (cost: smaller-metric routes are | ||
666 | preferred, default is 0) | ||
667 | dir -- direction (1 for direct, 0 for reverse, | ||
668 | default is 1) | ||
669 | ssn -- Source Sequence Number (time at the RA for | ||
670 | reverse routes. Default is 0) | ||
671 | dsn -- Destination Sequence Number (time at the DA | ||
672 | for direct routes. Default is 0) | ||
673 | hopcount -- hop count (currently unused, default is 0) | ||
674 | ttl -- TTL (Only used in reverse entries) | ||
675 | expiration -- entry expiration (in ticks, where a tick is | ||
676 | 1024us, or ~ 1ms. Use 0 for an indefinite | ||
677 | entry, default is 0) | ||
678 | sleepmode -- RA's sleep mode (currently unused, default is | ||
679 | 0) | ||
680 | snr -- SNR in the link to RA (currently unused, | ||
681 | default is 0) | ||
682 | |||
683 | The command does not return anything. | ||
684 | |||
685 | fwt_del | ||
686 | This command is used to remove an entry to the FWT table. The list of | ||
687 | parameters must follow the following structure: | ||
688 | |||
689 | iwpriv ethX fwt_del da ra [dir] | ||
690 | |||
691 | where the different parameters are:- | ||
692 | da -- DA MAC address (in the form "00:11:22:33:44:55") | ||
693 | ra -- RA MAC address (in the form "00:11:22:33:44:55") | ||
694 | dir -- direction (1 for direct, 0 for reverse, | ||
695 | default is 1) | ||
696 | |||
697 | The command does not return anything. | ||
698 | |||
699 | fwt_lookup | ||
700 | This command is used to get the best route in the FWT table to a given | ||
701 | host. The only parameter is the MAC address of the host that is being | ||
702 | looked for. | ||
703 | |||
704 | iwpriv ethX fwt_lookup da | ||
705 | |||
706 | where:- | ||
707 | da -- DA MAC address (in the form "00:11:22:33:44:55") | ||
708 | |||
709 | The command returns an output string identical to the one returned by | ||
710 | fwt_list described below. | ||
711 | |||
712 | |||
713 | fwt_list | ||
714 | This command is used to list a route from the FWT table. The only | ||
715 | parameter is the index into the table. If you want to list all the | ||
716 | routes in a table, start with index=0, and keep listing until you get a | ||
717 | "(null)" string. Note that the indicies may change as the fwt is | ||
718 | updated. It is expected that most users will not use fwt_list directly, | ||
719 | but that a utility similar to the traditional route command will be used | ||
720 | to invoke fwt_list over and over. | ||
721 | |||
722 | iwpriv ethX fwt_list index | ||
723 | |||
724 | The output is a string of the following form: | ||
725 | |||
726 | da ra metric dir ssn dsn hopcount ttl expiration sleepmode snr | ||
727 | |||
728 | where the different fields are:- | ||
729 | da -- DA MAC address (in the form "00:11:22:33:44:55") | ||
730 | ra -- RA MAC address (in the form "00:11:22:33:44:55") | ||
731 | metric -- route metric (cost: smaller-metric routes are preferred) | ||
732 | dir -- direction (1 for direct, 0 for reverse) | ||
733 | ssn -- Source Sequence Number (time at the RA for reverse routes) | ||
734 | dsn -- Destination Sequence Number (time at the DA for direct routes) | ||
735 | hopcount -- hop count (currently unused) | ||
736 | ttl -- TTL (only used in reverse entries) | ||
737 | expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry) | ||
738 | sleepmode -- RA's sleep mode (currently unused) | ||
739 | snr -- SNR in the link to RA (currently unused) | ||
740 | |||
741 | fwt_list_route | ||
742 | This command is used to list a route from the FWT table. The only | ||
743 | parameter is the route ID. If you want to list all the routes in a | ||
744 | table, start with rid=0, and keep incrementing rid until you get a | ||
745 | "(null)" string. This function is similar to fwt_list. The only | ||
746 | difference is the output format. Also note that this command is meant | ||
747 | for debugging. It is expected that users will use fwt_lookup and | ||
748 | fwt_list. One important reason for this is that the route id may change | ||
749 | as the route table is altered. | ||
750 | |||
751 | iwpriv ethX fwt_list_route rid | ||
752 | |||
753 | The output is a string of the following form: | ||
754 | |||
755 | da metric dir nid ssn dsn hopcount ttl expiration | ||
756 | |||
757 | where the different fields are:- | ||
758 | da -- DA MAC address (in the form "00:11:22:33:44:55") | ||
759 | metric -- route metric (cost: smaller-metric routes are preferred) | ||
760 | dir -- direction (1 for direct, 0 for reverse) | ||
761 | nid -- Next-hop (neighbor) host ID (nid) | ||
762 | ssn -- Source Sequence Number (time at the RA for reverse routes) | ||
763 | dsn -- Destination Sequence Number (time at the DA for direct routes) | ||
764 | hopcount -- hop count (currently unused) | ||
765 | ttl -- TTL count (only used in reverse entries) | ||
766 | expiration -- entry expiration (in ticks, where a tick is 1024us, or ~ 1ms. Use 0 for an indefinite entry) | ||
767 | |||
768 | fwt_list_neigh | ||
769 | This command is used to list a neighbor from the FWT table. The only | ||
770 | parameter is the neighbor ID. If you want to list all the neighbors in a | ||
771 | table, start with nid=0, and keep incrementing nid until you get a | ||
772 | "(null)" string. Note that the nid from a fwt_list_route command can be | ||
773 | used as an input to this command. Also note that this command is meant | ||
774 | mostly for debugging. It is expected that users will use fwt_lookup. | ||
775 | One important reason for this is that the neighbor id may change as the | ||
776 | neighbor table is altered. | ||
777 | |||
778 | iwpriv ethX fwt_list_neigh nid | ||
779 | |||
780 | The output is a string of the following form: | ||
781 | |||
782 | ra sleepmode snr references | ||
783 | |||
784 | where the different fields are:- | ||
785 | ra -- RA MAC address (in the form "00:11:22:33:44:55") | ||
786 | sleepmode -- RA's sleep mode (currently unused) | ||
787 | snr -- SNR in the link to RA (currently unused) | ||
788 | references -- RA's reference counter | ||
789 | |||
790 | fwt_reset | ||
791 | This command is used to reset the FWT table, getting rid of all the | ||
792 | entries. There are no input parameters. | ||
793 | |||
794 | iwpriv ethX fwt_reset | ||
795 | |||
796 | The command does not return anything. | ||
797 | |||
798 | fwt_cleanup | ||
799 | This command is used to perform user-based garbage recollection. The | ||
800 | FWT table is checked, and all the entries that are expired or invalid | ||
801 | are cleaned. Note that this is exported to the driver for debugging | ||
802 | purposes, as garbage collection is also fired by the firmware when in | ||
803 | space problems. There are no input parameters. | ||
804 | |||
805 | iwpriv ethX fwt_cleanup | ||
806 | |||
807 | The command does returns the number of invalid/expired routes deleted. | ||
808 | |||
809 | fwt_time | ||
810 | This command returns a card's internal time representation. It is this | ||
811 | time that is used to represent the expiration times of FWT entries. The | ||
812 | number is not consistent from card to card; it is simply a timer count. | ||
813 | The fwt_time command is used to inspect the timer so that expiration | ||
814 | times reported by fwt_list can be properly interpreted. | ||
815 | |||
816 | iwpriv ethX fwt_time | ||
817 | |||
818 | mesh_get_ttl | ||
819 | |||
820 | The mesh ttl is the number of hops a mesh packet can traverse before it | ||
821 | is dropped. This parameter is used to prevent infinite loops in the | ||
822 | mesh network. The value returned by this function is the ttl assigned | ||
823 | to all mesh packets. Currently there is no way to control the ttl on a | ||
824 | per packet or per socket basis. | ||
825 | |||
826 | iwpriv ethX mesh_get_ttl | ||
827 | |||
828 | mesh_set_ttl ttl | ||
829 | |||
830 | Set the ttl. The argument must be between 0 and 255. | ||
831 | |||
832 | iwpriv ethX mesh_set_ttl <ttl> | ||
833 | |||
834 | ========================= | ||
835 | ETHTOOL | ||
836 | ========================= | ||
837 | |||
838 | |||
839 | Use the -i option to retrieve version information from the driver. | ||
840 | |||
841 | # ethtool -i eth0 | ||
842 | driver: libertas | ||
843 | version: COMM-USB8388-318.p4 | ||
844 | firmware-version: 5.110.7 | ||
845 | bus-info: | ||
846 | |||
847 | Use the -e option to read the EEPROM contents of the card. | ||
848 | |||
849 | Usage: | ||
850 | ethtool -e ethX [raw on|off] [offset N] [length N] | ||
851 | |||
852 | -e retrieves and prints an EEPROM dump for the specified ethernet | ||
853 | device. When raw is enabled, then it dumps the raw EEPROM data | ||
854 | to stdout. The length and offset parameters allow dumping cer- | ||
855 | tain portions of the EEPROM. Default is to dump the entire EEP- | ||
856 | ROM. | ||
857 | |||
858 | # ethtool -e eth0 offset 0 length 16 | ||
859 | Offset Values | ||
860 | ------ ------ | ||
861 | 0x0000 38 33 30 58 00 00 34 f4 00 00 10 00 00 c4 17 00 | ||
862 | |||
863 | ======================== | ||
864 | DEBUGFS COMMANDS | ||
865 | ======================== | ||
866 | |||
867 | those commands are used via debugfs interface | ||
868 | |||
869 | =========== | ||
870 | rdmac | ||
871 | rdbbp | ||
872 | rdrf | ||
873 | These commands are used to read the MAC, BBP and RF registers from the | ||
874 | card. These commands take one parameter that specifies the offset | ||
875 | location that is to be read. This parameter must be specified in | ||
876 | hexadecimal (its possible to preceed preceding the number with a "0x"). | ||
877 | |||
878 | Path: /debugfs/libertas_wireless/ethX/registers/ | ||
879 | |||
880 | Usage: | ||
881 | echo "0xa123" > rdmac ; cat rdmac | ||
882 | echo "0xa123" > rdbbp ; cat rdbbp | ||
883 | echo "0xa123" > rdrf ; cat rdrf | ||
884 | wrmac | ||
885 | wrbbp | ||
886 | wrrf | ||
887 | These commands are used to write the MAC, BBP and RF registers in the | ||
888 | card. These commands take two parameters that specify the offset | ||
889 | location and the value that is to be written. This parameters must | ||
890 | be specified in hexadecimal (its possible to preceed the number | ||
891 | with a "0x"). | ||
892 | |||
893 | Usage: | ||
894 | echo "0xa123 0xaa" > wrmac | ||
895 | echo "0xa123 0xaa" > wrbbp | ||
896 | echo "0xa123 0xaa" > wrrf | ||
897 | |||
898 | sleepparams | ||
899 | This command is used to set the sleepclock configurations | ||
900 | |||
901 | Path: /debugfs/libertas_wireless/ethX/ | ||
902 | |||
903 | Usage: | ||
904 | cat sleepparams: reads the current sleepclock configuration | ||
905 | |||
906 | echo "p1 p2 p3 p4 p5 p6" > sleepparams: writes the sleepclock configuration. | ||
907 | |||
908 | where: | ||
909 | p1 is Sleep clock error in ppm (0-65535) | ||
910 | p2 is Wakeup offset in usec (0-65535) | ||
911 | p3 is Clock stabilization time in usec (0-65535) | ||
912 | p4 is Control periodic calibration (0-2) | ||
913 | p5 is Control the use of external sleep clock (0-2) | ||
914 | p6 is reserved for debug (0-65535) | ||
915 | |||
916 | subscribed_events | ||
917 | |||
918 | The subscribed_events directory contains the interface for the | ||
919 | subscribed events API. | ||
920 | |||
921 | Path: /debugfs/libertas_wireless/ethX/subscribed_events/ | ||
922 | |||
923 | Each event is represented by a filename. Each filename consists of the | ||
924 | following three fields: | ||
925 | Value Frequency Subscribed | ||
926 | |||
927 | To read the current values for a given event, do: | ||
928 | cat event | ||
929 | To set the current values, do: | ||
930 | echo "60 2 1" > event | ||
931 | |||
932 | Frequency field specifies the reporting frequency for this event. | ||
933 | If it is set to 0, then the event is reported only once, and then | ||
934 | automatically unsubscribed. If it is set to 1, then the event is | ||
935 | reported every time it occurs. If it is set to N, then the event is | ||
936 | reported every Nth time it occurs. | ||
937 | |||
938 | beacon_missed | ||
939 | Value field specifies the number of consecutive missing beacons which | ||
940 | triggers the LINK_LOSS event. This event is generated only once after | ||
941 | which the firmware resets its state. At initialization, the LINK_LOSS | ||
942 | event is subscribed by default. The default value of MissedBeacons is | ||
943 | 60. | ||
944 | |||
945 | failure_count | ||
946 | Value field specifies the consecutive failure count threshold which | ||
947 | triggers the generation of the MAX_FAIL event. Once this event is | ||
948 | generated, the consecutive failure count is reset to 0. | ||
949 | At initialization, the MAX_FAIL event is NOT subscribed by | ||
950 | default. | ||
951 | |||
952 | high_rssi | ||
953 | This event is generated when the average received RSSI in beacons goes | ||
954 | above a threshold, specified by Value. | ||
955 | |||
956 | low_rssi | ||
957 | This event is generated when the average received RSSI in beacons goes | ||
958 | below a threshold, specified by Value. | ||
959 | |||
960 | high_snr | ||
961 | This event is generated when the average received SNR in beacons goes | ||
962 | above a threshold, specified by Value. | ||
963 | |||
964 | low_snr | ||
965 | This event is generated when the average received SNR in beacons goes | ||
966 | below a threshold, specified by Value. | ||
967 | |||
968 | extscan | ||
969 | This command is used to do a specific scan. | ||
970 | |||
971 | Path: /debugfs/libertas_wireless/ethX/ | ||
972 | |||
973 | Usage: echo "SSID" > extscan | ||
974 | |||
975 | Example: | ||
976 | echo "LINKSYS-AP" > extscan | ||
977 | |||
978 | To see the results of use getscantable command. | ||
979 | |||
980 | getscantable | ||
981 | |||
982 | Display the current contents of the driver scan table (ie. get the | ||
983 | scan results). | ||
984 | |||
985 | Path: /debugfs/libertas_wireless/ethX/ | ||
986 | |||
987 | Usage: | ||
988 | cat getscantable | ||
989 | |||
990 | setuserscan | ||
991 | Initiate a customized scan and retrieve the results | ||
992 | |||
993 | |||
994 | Path: /debugfs/libertas_wireless/ethX/ | ||
995 | |||
996 | Usage: | ||
997 | echo "[ARGS]" > setuserscan | ||
998 | |||
999 | where [ARGS]: | ||
1000 | |||
1001 | chan=[chan#][band][mode] where band is [a,b,g] and mode is | ||
1002 | blank for active or 'p' for passive | ||
1003 | bssid=xx:xx:xx:xx:xx:xx specify a BSSID filter for the scan | ||
1004 | ssid="[SSID]" specify a SSID filter for the scan | ||
1005 | keep=[0 or 1] keep the previous scan results (1), discard (0) | ||
1006 | dur=[scan time] time to scan for each channel in milliseconds | ||
1007 | probes=[#] number of probe requests to send on each chan | ||
1008 | type=[1,2,3] BSS type: 1 (Infra), 2(Adhoc), 3(Any) | ||
1009 | |||
1010 | Any combination of the above arguments can be supplied on the command line. | ||
1011 | If the chan token is absent, a full channel scan will be completed by | ||
1012 | the driver. If the dur or probes tokens are absent, the driver default | ||
1013 | setting will be used. The bssid and ssid fields, if blank, | ||
1014 | will produce an unfiltered scan. The type field will default to 3 (Any) | ||
1015 | and the keep field will default to 0 (Discard). | ||
1016 | |||
1017 | Examples: | ||
1018 | 1) Perform an active scan on channels 1, 6, and 11 in the 'g' band: | ||
1019 | echo "chan=1g,6g,11g" > setuserscan | ||
1020 | |||
1021 | 2) Perform a passive scan on channel 11 for 20 ms: | ||
1022 | echo "chan=11gp dur=20" > setuserscan | ||
1023 | |||
1024 | 3) Perform an active scan on channels 1, 6, and 11; and a passive scan on | ||
1025 | channel 36 in the 'a' band: | ||
1026 | |||
1027 | echo "chan=1g,6g,11g,36ap" > setuserscan | ||
1028 | |||
1029 | 4) Perform an active scan on channel 6 and 36 for a specific SSID: | ||
1030 | echo "chan=6g,36a ssid="TestAP"" > setuserscan | ||
1031 | |||
1032 | 5) Scan all available channels (B/G, A bands) for a specific BSSID, keep | ||
1033 | the current scan table intact, update existing or append new scan data: | ||
1034 | echo "bssid=00:50:43:20:12:82 keep=1" > setuserscan | ||
1035 | |||
1036 | 6) Scan channel 6, for all infrastructure networks, sending two probe | ||
1037 | requests. Keep the previous scan table intact. Update any duplicate | ||
1038 | BSSID/SSID matches with the new scan data: | ||
1039 | echo "chan=6g type=1 probes=2 keep=1" > setuserscan | ||
1040 | |||
1041 | All entries in the scan table (not just the new scan data when keep=1) | ||
1042 | will be displayed upon completion by use of the getscantable ioctl. | ||
1043 | |||
1044 | ============================================================================== | ||
diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c new file mode 100644 index 000000000000..b55c7f57aca8 --- /dev/null +++ b/drivers/net/wireless/libertas/assoc.c | |||
@@ -0,0 +1,588 @@ | |||
1 | /* Copyright (C) 2006, Red Hat, Inc. */ | ||
2 | |||
3 | #include <linux/bitops.h> | ||
4 | #include <net/ieee80211.h> | ||
5 | |||
6 | #include "assoc.h" | ||
7 | #include "join.h" | ||
8 | #include "decl.h" | ||
9 | #include "hostcmd.h" | ||
10 | #include "host.h" | ||
11 | |||
12 | |||
13 | static const u8 bssid_any[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | ||
14 | static const u8 bssid_off[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
15 | |||
16 | static int assoc_helper_essid(wlan_private *priv, | ||
17 | struct assoc_request * assoc_req) | ||
18 | { | ||
19 | wlan_adapter *adapter = priv->adapter; | ||
20 | int ret = 0; | ||
21 | int i; | ||
22 | |||
23 | ENTER(); | ||
24 | |||
25 | lbs_pr_debug(1, "New SSID requested: %s\n", assoc_req->ssid.ssid); | ||
26 | if (assoc_req->mode == wlan802_11infrastructure) { | ||
27 | if (adapter->prescan) { | ||
28 | libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 1); | ||
29 | } | ||
30 | |||
31 | i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, | ||
32 | NULL, wlan802_11infrastructure); | ||
33 | if (i >= 0) { | ||
34 | lbs_pr_debug(1, | ||
35 | "SSID found in scan list ... associating...\n"); | ||
36 | |||
37 | ret = wlan_associate(priv, &adapter->scantable[i]); | ||
38 | if (ret == 0) { | ||
39 | memcpy(&assoc_req->bssid, | ||
40 | &adapter->scantable[i].macaddress, | ||
41 | ETH_ALEN); | ||
42 | } | ||
43 | } else { | ||
44 | lbs_pr_debug(1, "SSID '%s' not found; cannot associate\n", | ||
45 | assoc_req->ssid.ssid); | ||
46 | } | ||
47 | } else if (assoc_req->mode == wlan802_11ibss) { | ||
48 | /* Scan for the network, do not save previous results. Stale | ||
49 | * scan data will cause us to join a non-existant adhoc network | ||
50 | */ | ||
51 | libertas_send_specific_SSID_scan(priv, &assoc_req->ssid, 0); | ||
52 | |||
53 | /* Search for the requested SSID in the scan table */ | ||
54 | i = libertas_find_SSID_in_list(adapter, &assoc_req->ssid, NULL, | ||
55 | wlan802_11ibss); | ||
56 | if (i >= 0) { | ||
57 | lbs_pr_debug(1, "SSID found at %d in List, so join\n", ret); | ||
58 | libertas_join_adhoc_network(priv, &adapter->scantable[i]); | ||
59 | } else { | ||
60 | /* else send START command */ | ||
61 | lbs_pr_debug(1, "SSID not found in list, so creating adhoc" | ||
62 | " with SSID '%s'\n", assoc_req->ssid.ssid); | ||
63 | libertas_start_adhoc_network(priv, &assoc_req->ssid); | ||
64 | } | ||
65 | memcpy(&assoc_req->bssid, &adapter->current_addr, ETH_ALEN); | ||
66 | } | ||
67 | |||
68 | LEAVE(); | ||
69 | return ret; | ||
70 | } | ||
71 | |||
72 | |||
73 | static int assoc_helper_bssid(wlan_private *priv, | ||
74 | struct assoc_request * assoc_req) | ||
75 | { | ||
76 | wlan_adapter *adapter = priv->adapter; | ||
77 | int i, ret = 0; | ||
78 | |||
79 | ENTER(); | ||
80 | |||
81 | lbs_pr_debug(1, "ASSOC: WAP: BSSID = " MAC_FMT "\n", | ||
82 | MAC_ARG(assoc_req->bssid)); | ||
83 | |||
84 | /* Search for index position in list for requested MAC */ | ||
85 | i = libertas_find_BSSID_in_list(adapter, assoc_req->bssid, | ||
86 | assoc_req->mode); | ||
87 | if (i < 0) { | ||
88 | lbs_pr_debug(1, "ASSOC: WAP: BSSID " MAC_FMT " not found, " | ||
89 | "cannot associate.\n", MAC_ARG(assoc_req->bssid)); | ||
90 | goto out; | ||
91 | } | ||
92 | |||
93 | if (assoc_req->mode == wlan802_11infrastructure) { | ||
94 | ret = wlan_associate(priv, &adapter->scantable[i]); | ||
95 | lbs_pr_debug(1, "ASSOC: return from wlan_associate(bssd) was %d\n", ret); | ||
96 | } else if (assoc_req->mode == wlan802_11ibss) { | ||
97 | libertas_join_adhoc_network(priv, &adapter->scantable[i]); | ||
98 | } | ||
99 | memcpy(&assoc_req->ssid, &adapter->scantable[i].ssid, | ||
100 | sizeof(struct WLAN_802_11_SSID)); | ||
101 | |||
102 | out: | ||
103 | LEAVE(); | ||
104 | return ret; | ||
105 | } | ||
106 | |||
107 | |||
108 | static int assoc_helper_associate(wlan_private *priv, | ||
109 | struct assoc_request * assoc_req) | ||
110 | { | ||
111 | int ret = 0, done = 0; | ||
112 | |||
113 | /* If we're given and 'any' BSSID, try associating based on SSID */ | ||
114 | |||
115 | if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { | ||
116 | if (memcmp(bssid_any, assoc_req->bssid, ETH_ALEN) | ||
117 | && memcmp(bssid_off, assoc_req->bssid, ETH_ALEN)) { | ||
118 | ret = assoc_helper_bssid(priv, assoc_req); | ||
119 | done = 1; | ||
120 | if (ret) { | ||
121 | lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret); | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | |||
126 | if (!done && test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { | ||
127 | ret = assoc_helper_essid(priv, assoc_req); | ||
128 | if (ret) { | ||
129 | lbs_pr_debug(1, "ASSOC: bssid: ret = %d\n", ret); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | |||
137 | static int assoc_helper_mode(wlan_private *priv, | ||
138 | struct assoc_request * assoc_req) | ||
139 | { | ||
140 | wlan_adapter *adapter = priv->adapter; | ||
141 | int ret = 0; | ||
142 | |||
143 | ENTER(); | ||
144 | |||
145 | if (assoc_req->mode == adapter->inframode) { | ||
146 | LEAVE(); | ||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | if (assoc_req->mode == wlan802_11infrastructure) { | ||
151 | if (adapter->psstate != PS_STATE_FULL_POWER) | ||
152 | libertas_ps_wakeup(priv, cmd_option_waitforrsp); | ||
153 | adapter->psmode = wlan802_11powermodecam; | ||
154 | } | ||
155 | |||
156 | adapter->inframode = assoc_req->mode; | ||
157 | ret = libertas_prepare_and_send_command(priv, | ||
158 | cmd_802_11_snmp_mib, | ||
159 | 0, cmd_option_waitforrsp, | ||
160 | OID_802_11_INFRASTRUCTURE_MODE, | ||
161 | (void *) assoc_req->mode); | ||
162 | |||
163 | LEAVE(); | ||
164 | return ret; | ||
165 | } | ||
166 | |||
167 | |||
168 | static int assoc_helper_wep_keys(wlan_private *priv, | ||
169 | struct assoc_request * assoc_req) | ||
170 | { | ||
171 | wlan_adapter *adapter = priv->adapter; | ||
172 | int i; | ||
173 | int ret = 0; | ||
174 | |||
175 | ENTER(); | ||
176 | |||
177 | /* Set or remove WEP keys */ | ||
178 | if ( assoc_req->wep_keys[0].len | ||
179 | || assoc_req->wep_keys[1].len | ||
180 | || assoc_req->wep_keys[2].len | ||
181 | || assoc_req->wep_keys[3].len) { | ||
182 | ret = libertas_prepare_and_send_command(priv, | ||
183 | cmd_802_11_set_wep, | ||
184 | cmd_act_add, | ||
185 | cmd_option_waitforrsp, | ||
186 | 0, assoc_req); | ||
187 | } else { | ||
188 | ret = libertas_prepare_and_send_command(priv, | ||
189 | cmd_802_11_set_wep, | ||
190 | cmd_act_remove, | ||
191 | cmd_option_waitforrsp, | ||
192 | 0, NULL); | ||
193 | } | ||
194 | |||
195 | if (ret) | ||
196 | goto out; | ||
197 | |||
198 | /* enable/disable the MAC's WEP packet filter */ | ||
199 | if (assoc_req->secinfo.WEPstatus == wlan802_11WEPenabled) | ||
200 | adapter->currentpacketfilter |= cmd_act_mac_wep_enable; | ||
201 | else | ||
202 | adapter->currentpacketfilter &= ~cmd_act_mac_wep_enable; | ||
203 | ret = libertas_set_mac_packet_filter(priv); | ||
204 | if (ret) | ||
205 | goto out; | ||
206 | |||
207 | mutex_lock(&adapter->lock); | ||
208 | |||
209 | /* Copy WEP keys into adapter wep key fields */ | ||
210 | for (i = 0; i < 4; i++) { | ||
211 | memcpy(&adapter->wep_keys[i], &assoc_req->wep_keys[i], | ||
212 | sizeof(struct WLAN_802_11_KEY)); | ||
213 | } | ||
214 | adapter->wep_tx_keyidx = assoc_req->wep_tx_keyidx; | ||
215 | |||
216 | mutex_unlock(&adapter->lock); | ||
217 | |||
218 | out: | ||
219 | LEAVE(); | ||
220 | return ret; | ||
221 | } | ||
222 | |||
223 | static int assoc_helper_secinfo(wlan_private *priv, | ||
224 | struct assoc_request * assoc_req) | ||
225 | { | ||
226 | wlan_adapter *adapter = priv->adapter; | ||
227 | int ret = 0; | ||
228 | |||
229 | ENTER(); | ||
230 | |||
231 | memcpy(&adapter->secinfo, &assoc_req->secinfo, | ||
232 | sizeof(struct wlan_802_11_security)); | ||
233 | |||
234 | ret = libertas_set_mac_packet_filter(priv); | ||
235 | |||
236 | LEAVE(); | ||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | |||
241 | static int assoc_helper_wpa_keys(wlan_private *priv, | ||
242 | struct assoc_request * assoc_req) | ||
243 | { | ||
244 | int ret = 0; | ||
245 | |||
246 | ENTER(); | ||
247 | |||
248 | /* enable/Disable RSN */ | ||
249 | ret = libertas_prepare_and_send_command(priv, | ||
250 | cmd_802_11_enable_rsn, | ||
251 | cmd_act_set, | ||
252 | cmd_option_waitforrsp, | ||
253 | 0, assoc_req); | ||
254 | if (ret) | ||
255 | goto out; | ||
256 | |||
257 | ret = libertas_prepare_and_send_command(priv, | ||
258 | cmd_802_11_key_material, | ||
259 | cmd_act_set, | ||
260 | cmd_option_waitforrsp, | ||
261 | 0, assoc_req); | ||
262 | |||
263 | out: | ||
264 | LEAVE(); | ||
265 | return ret; | ||
266 | } | ||
267 | |||
268 | |||
269 | static int assoc_helper_wpa_ie(wlan_private *priv, | ||
270 | struct assoc_request * assoc_req) | ||
271 | { | ||
272 | wlan_adapter *adapter = priv->adapter; | ||
273 | int ret = 0; | ||
274 | |||
275 | ENTER(); | ||
276 | |||
277 | if (assoc_req->secinfo.WPAenabled || assoc_req->secinfo.WPA2enabled) { | ||
278 | memcpy(&adapter->wpa_ie, &assoc_req->wpa_ie, assoc_req->wpa_ie_len); | ||
279 | adapter->wpa_ie_len = assoc_req->wpa_ie_len; | ||
280 | } else { | ||
281 | memset(&adapter->wpa_ie, 0, MAX_WPA_IE_LEN); | ||
282 | adapter->wpa_ie_len = 0; | ||
283 | } | ||
284 | |||
285 | LEAVE(); | ||
286 | return ret; | ||
287 | } | ||
288 | |||
289 | |||
290 | static int should_deauth_infrastructure(wlan_adapter *adapter, | ||
291 | struct assoc_request * assoc_req) | ||
292 | { | ||
293 | if (adapter->connect_status != libertas_connected) | ||
294 | return 0; | ||
295 | |||
296 | if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { | ||
297 | lbs_pr_debug(1, "Deauthenticating due to new SSID in " | ||
298 | " configuration request.\n"); | ||
299 | return 1; | ||
300 | } | ||
301 | |||
302 | if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { | ||
303 | if (adapter->secinfo.authmode != | ||
304 | assoc_req->secinfo.authmode) { | ||
305 | lbs_pr_debug(1, "Deauthenticating due to updated security " | ||
306 | "info in configuration request.\n"); | ||
307 | return 1; | ||
308 | } | ||
309 | } | ||
310 | |||
311 | if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { | ||
312 | lbs_pr_debug(1, "Deauthenticating due to new BSSID in " | ||
313 | " configuration request.\n"); | ||
314 | return 1; | ||
315 | } | ||
316 | |||
317 | /* FIXME: deal with 'auto' mode somehow */ | ||
318 | if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { | ||
319 | if (assoc_req->mode != wlan802_11infrastructure) | ||
320 | return 1; | ||
321 | } | ||
322 | |||
323 | return 0; | ||
324 | } | ||
325 | |||
326 | |||
327 | static int should_stop_adhoc(wlan_adapter *adapter, | ||
328 | struct assoc_request * assoc_req) | ||
329 | { | ||
330 | if (adapter->connect_status != libertas_connected) | ||
331 | return 0; | ||
332 | |||
333 | if (adapter->curbssparams.ssid.ssidlength != assoc_req->ssid.ssidlength) | ||
334 | return 1; | ||
335 | if (memcmp(adapter->curbssparams.ssid.ssid, assoc_req->ssid.ssid, | ||
336 | sizeof(struct WLAN_802_11_SSID))) | ||
337 | return 1; | ||
338 | |||
339 | /* FIXME: deal with 'auto' mode somehow */ | ||
340 | if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { | ||
341 | if (assoc_req->mode != wlan802_11ibss) | ||
342 | return 1; | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | |||
349 | void wlan_association_worker(struct work_struct *work) | ||
350 | { | ||
351 | wlan_private *priv = container_of(work, wlan_private, assoc_work.work); | ||
352 | wlan_adapter *adapter = priv->adapter; | ||
353 | struct assoc_request * assoc_req = NULL; | ||
354 | int ret = 0; | ||
355 | int find_any_ssid = 0; | ||
356 | |||
357 | ENTER(); | ||
358 | |||
359 | mutex_lock(&adapter->lock); | ||
360 | assoc_req = adapter->assoc_req; | ||
361 | adapter->assoc_req = NULL; | ||
362 | mutex_unlock(&adapter->lock); | ||
363 | |||
364 | if (!assoc_req) { | ||
365 | LEAVE(); | ||
366 | return; | ||
367 | } | ||
368 | |||
369 | lbs_pr_debug(1, "ASSOC: starting new association request: flags = 0x%lX\n", | ||
370 | assoc_req->flags); | ||
371 | |||
372 | /* If 'any' SSID was specified, find an SSID to associate with */ | ||
373 | if (test_bit(ASSOC_FLAG_SSID, &assoc_req->flags) | ||
374 | && !assoc_req->ssid.ssidlength) | ||
375 | find_any_ssid = 1; | ||
376 | |||
377 | /* But don't use 'any' SSID if there's a valid locked BSSID to use */ | ||
378 | if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { | ||
379 | if (memcmp(&assoc_req->bssid, bssid_any, ETH_ALEN) | ||
380 | && memcmp(&assoc_req->bssid, bssid_off, ETH_ALEN)) | ||
381 | find_any_ssid = 0; | ||
382 | } | ||
383 | |||
384 | if (find_any_ssid) { | ||
385 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode; | ||
386 | |||
387 | ret = libertas_find_best_network_SSID(priv, &assoc_req->ssid, | ||
388 | assoc_req->mode, &new_mode); | ||
389 | if (ret) { | ||
390 | lbs_pr_debug(1, "Could not find best network\n"); | ||
391 | ret = -ENETUNREACH; | ||
392 | goto out; | ||
393 | } | ||
394 | |||
395 | /* Ensure we switch to the mode of the AP */ | ||
396 | if (assoc_req->mode == wlan802_11autounknown) { | ||
397 | set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); | ||
398 | assoc_req->mode = new_mode; | ||
399 | } | ||
400 | } | ||
401 | |||
402 | /* | ||
403 | * Check if the attributes being changing require deauthentication | ||
404 | * from the currently associated infrastructure access point. | ||
405 | */ | ||
406 | if (adapter->inframode == wlan802_11infrastructure) { | ||
407 | if (should_deauth_infrastructure(adapter, assoc_req)) { | ||
408 | ret = libertas_send_deauthentication(priv); | ||
409 | if (ret) { | ||
410 | lbs_pr_debug(1, "Deauthentication due to new " | ||
411 | "configuration request failed: %d\n", | ||
412 | ret); | ||
413 | } | ||
414 | } | ||
415 | } else if (adapter->inframode == wlan802_11ibss) { | ||
416 | if (should_stop_adhoc(adapter, assoc_req)) { | ||
417 | ret = libertas_stop_adhoc_network(priv); | ||
418 | if (ret) { | ||
419 | lbs_pr_debug(1, "Teardown of AdHoc network due to " | ||
420 | "new configuration request failed: %d\n", | ||
421 | ret); | ||
422 | } | ||
423 | |||
424 | } | ||
425 | } | ||
426 | |||
427 | /* Send the various configuration bits to the firmware */ | ||
428 | if (test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) { | ||
429 | ret = assoc_helper_mode(priv, assoc_req); | ||
430 | if (ret) { | ||
431 | lbs_pr_debug(1, "ASSOC(:%d) mode: ret = %d\n", __LINE__, ret); | ||
432 | goto out; | ||
433 | } | ||
434 | } | ||
435 | |||
436 | if ( test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags) | ||
437 | || test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) { | ||
438 | ret = assoc_helper_wep_keys(priv, assoc_req); | ||
439 | if (ret) { | ||
440 | lbs_pr_debug(1, "ASSOC(:%d) wep_keys: ret = %d\n", __LINE__, ret); | ||
441 | goto out; | ||
442 | } | ||
443 | } | ||
444 | |||
445 | if (test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { | ||
446 | ret = assoc_helper_secinfo(priv, assoc_req); | ||
447 | if (ret) { | ||
448 | lbs_pr_debug(1, "ASSOC(:%d) secinfo: ret = %d\n", __LINE__, ret); | ||
449 | goto out; | ||
450 | } | ||
451 | } | ||
452 | |||
453 | if (test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { | ||
454 | ret = assoc_helper_wpa_ie(priv, assoc_req); | ||
455 | if (ret) { | ||
456 | lbs_pr_debug(1, "ASSOC(:%d) wpa_ie: ret = %d\n", __LINE__, ret); | ||
457 | goto out; | ||
458 | } | ||
459 | } | ||
460 | |||
461 | if (test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags) | ||
462 | || test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { | ||
463 | ret = assoc_helper_wpa_keys(priv, assoc_req); | ||
464 | if (ret) { | ||
465 | lbs_pr_debug(1, "ASSOC(:%d) wpa_keys: ret = %d\n", __LINE__, ret); | ||
466 | goto out; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | /* SSID/BSSID should be the _last_ config option set, because they | ||
471 | * trigger the association attempt. | ||
472 | */ | ||
473 | if (test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags) | ||
474 | || test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { | ||
475 | int success = 1; | ||
476 | |||
477 | ret = assoc_helper_associate(priv, assoc_req); | ||
478 | if (ret) { | ||
479 | lbs_pr_debug(1, "ASSOC: association attempt unsuccessful: %d\n", | ||
480 | ret); | ||
481 | success = 0; | ||
482 | } | ||
483 | |||
484 | if (adapter->connect_status != libertas_connected) { | ||
485 | lbs_pr_debug(1, "ASSOC: assoication attempt unsuccessful, " | ||
486 | "not connected.\n"); | ||
487 | success = 0; | ||
488 | } | ||
489 | |||
490 | if (success) { | ||
491 | lbs_pr_debug(1, "ASSOC: association attempt successful. " | ||
492 | "Associated to '%s' (" MAC_FMT ")\n", | ||
493 | assoc_req->ssid.ssid, MAC_ARG(assoc_req->bssid)); | ||
494 | libertas_prepare_and_send_command(priv, | ||
495 | cmd_802_11_rssi, | ||
496 | 0, cmd_option_waitforrsp, 0, NULL); | ||
497 | |||
498 | libertas_prepare_and_send_command(priv, | ||
499 | cmd_802_11_get_log, | ||
500 | 0, cmd_option_waitforrsp, 0, NULL); | ||
501 | } else { | ||
502 | |||
503 | ret = -1; | ||
504 | } | ||
505 | } | ||
506 | |||
507 | out: | ||
508 | if (ret) { | ||
509 | lbs_pr_debug(1, "ASSOC: reconfiguration attempt unsuccessful: %d\n", | ||
510 | ret); | ||
511 | } | ||
512 | kfree(assoc_req); | ||
513 | LEAVE(); | ||
514 | } | ||
515 | |||
516 | |||
517 | /* | ||
518 | * Caller MUST hold any necessary locks | ||
519 | */ | ||
520 | struct assoc_request * wlan_get_association_request(wlan_adapter *adapter) | ||
521 | { | ||
522 | struct assoc_request * assoc_req; | ||
523 | |||
524 | if (!adapter->assoc_req) { | ||
525 | adapter->assoc_req = kzalloc(sizeof(struct assoc_request), GFP_KERNEL); | ||
526 | if (!adapter->assoc_req) { | ||
527 | lbs_pr_info("Not enough memory to allocate association" | ||
528 | " request!\n"); | ||
529 | return NULL; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | /* Copy current configuration attributes to the association request, | ||
534 | * but don't overwrite any that are already set. | ||
535 | */ | ||
536 | assoc_req = adapter->assoc_req; | ||
537 | if (!test_bit(ASSOC_FLAG_SSID, &assoc_req->flags)) { | ||
538 | memcpy(&assoc_req->ssid, adapter->curbssparams.ssid.ssid, | ||
539 | adapter->curbssparams.ssid.ssidlength); | ||
540 | } | ||
541 | |||
542 | if (!test_bit(ASSOC_FLAG_CHANNEL, &assoc_req->flags)) | ||
543 | assoc_req->channel = adapter->curbssparams.channel; | ||
544 | |||
545 | if (!test_bit(ASSOC_FLAG_MODE, &assoc_req->flags)) | ||
546 | assoc_req->mode = adapter->inframode; | ||
547 | |||
548 | if (!test_bit(ASSOC_FLAG_BSSID, &assoc_req->flags)) { | ||
549 | memcpy(&assoc_req->bssid, adapter->curbssparams.bssid, | ||
550 | ETH_ALEN); | ||
551 | } | ||
552 | |||
553 | if (!test_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags)) { | ||
554 | int i; | ||
555 | for (i = 0; i < 4; i++) { | ||
556 | memcpy(&assoc_req->wep_keys[i], &adapter->wep_keys[i], | ||
557 | sizeof(struct WLAN_802_11_KEY)); | ||
558 | } | ||
559 | } | ||
560 | |||
561 | if (!test_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags)) | ||
562 | assoc_req->wep_tx_keyidx = adapter->wep_tx_keyidx; | ||
563 | |||
564 | if (!test_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags)) { | ||
565 | memcpy(&assoc_req->wpa_mcast_key, &adapter->wpa_mcast_key, | ||
566 | sizeof(struct WLAN_802_11_KEY)); | ||
567 | } | ||
568 | |||
569 | if (!test_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags)) { | ||
570 | memcpy(&assoc_req->wpa_unicast_key, &adapter->wpa_unicast_key, | ||
571 | sizeof(struct WLAN_802_11_KEY)); | ||
572 | } | ||
573 | |||
574 | if (!test_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags)) { | ||
575 | memcpy(&assoc_req->secinfo, &adapter->secinfo, | ||
576 | sizeof(struct wlan_802_11_security)); | ||
577 | } | ||
578 | |||
579 | if (!test_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags)) { | ||
580 | memcpy(&assoc_req->wpa_ie, &adapter->wpa_ie, | ||
581 | MAX_WPA_IE_LEN); | ||
582 | assoc_req->wpa_ie_len = adapter->wpa_ie_len; | ||
583 | } | ||
584 | |||
585 | return assoc_req; | ||
586 | } | ||
587 | |||
588 | |||
diff --git a/drivers/net/wireless/libertas/assoc.h b/drivers/net/wireless/libertas/assoc.h new file mode 100644 index 000000000000..2ffd82d99b34 --- /dev/null +++ b/drivers/net/wireless/libertas/assoc.h | |||
@@ -0,0 +1,30 @@ | |||
1 | /* Copyright (C) 2006, Red Hat, Inc. */ | ||
2 | |||
3 | #ifndef _WLAN_ASSOC_H_ | ||
4 | #define _WLAN_ASSOC_H_ | ||
5 | |||
6 | #include "dev.h" | ||
7 | |||
8 | void wlan_association_worker(struct work_struct *work); | ||
9 | |||
10 | struct assoc_request * wlan_get_association_request(wlan_adapter *adapter); | ||
11 | |||
12 | #define ASSOC_DELAY (HZ / 2) | ||
13 | static inline void wlan_postpone_association_work(wlan_private *priv) | ||
14 | { | ||
15 | if (priv->adapter->surpriseremoved) | ||
16 | return; | ||
17 | cancel_delayed_work(&priv->assoc_work); | ||
18 | queue_delayed_work(priv->assoc_thread, &priv->assoc_work, ASSOC_DELAY); | ||
19 | } | ||
20 | |||
21 | static inline void wlan_cancel_association_work(wlan_private *priv) | ||
22 | { | ||
23 | cancel_delayed_work(&priv->assoc_work); | ||
24 | if (priv->adapter->assoc_req) { | ||
25 | kfree(priv->adapter->assoc_req); | ||
26 | priv->adapter->assoc_req = NULL; | ||
27 | } | ||
28 | } | ||
29 | |||
30 | #endif /* _WLAN_ASSOC_H */ | ||
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c new file mode 100644 index 000000000000..bfdac58b5c06 --- /dev/null +++ b/drivers/net/wireless/libertas/cmd.c | |||
@@ -0,0 +1,1958 @@ | |||
1 | /** | ||
2 | * This file contains the handling of command. | ||
3 | * It prepares command and sends it to firmware when it is ready. | ||
4 | */ | ||
5 | |||
6 | #include <net/iw_handler.h> | ||
7 | #include "host.h" | ||
8 | #include "hostcmd.h" | ||
9 | #include "sbi.h" | ||
10 | #include "decl.h" | ||
11 | #include "defs.h" | ||
12 | #include "dev.h" | ||
13 | #include "join.h" | ||
14 | #include "wext.h" | ||
15 | |||
16 | static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode); | ||
17 | |||
18 | static u16 commands_allowed_in_ps[] = { | ||
19 | cmd_802_11_rssi, | ||
20 | }; | ||
21 | |||
22 | /** | ||
23 | * @brief This function checks if the commans is allowed | ||
24 | * in PS mode not. | ||
25 | * | ||
26 | * @param command the command ID | ||
27 | * @return TRUE or FALSE | ||
28 | */ | ||
29 | static u8 is_command_allowed_in_ps(u16 command) | ||
30 | { | ||
31 | int count = sizeof(commands_allowed_in_ps) | ||
32 | / sizeof(commands_allowed_in_ps[0]); | ||
33 | int i; | ||
34 | |||
35 | for (i = 0; i < count; i++) { | ||
36 | if (command == cpu_to_le16(commands_allowed_in_ps[i])) | ||
37 | return 1; | ||
38 | } | ||
39 | |||
40 | return 0; | ||
41 | } | ||
42 | |||
43 | static int wlan_cmd_hw_spec(wlan_private * priv, struct cmd_ds_command *cmd) | ||
44 | { | ||
45 | struct cmd_ds_get_hw_spec *hwspec = &cmd->params.hwspec; | ||
46 | |||
47 | ENTER(); | ||
48 | |||
49 | cmd->command = cpu_to_le16(cmd_get_hw_spec); | ||
50 | cmd->size = | ||
51 | cpu_to_le16(sizeof(struct cmd_ds_get_hw_spec) + S_DS_GEN); | ||
52 | memcpy(hwspec->permanentaddr, priv->adapter->current_addr, ETH_ALEN); | ||
53 | |||
54 | LEAVE(); | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int wlan_cmd_802_11_ps_mode(wlan_private * priv, | ||
59 | struct cmd_ds_command *cmd, | ||
60 | u16 cmd_action) | ||
61 | { | ||
62 | struct cmd_ds_802_11_ps_mode *psm = &cmd->params.psmode; | ||
63 | u16 action = cmd_action; | ||
64 | wlan_adapter *adapter = priv->adapter; | ||
65 | |||
66 | ENTER(); | ||
67 | |||
68 | cmd->command = cpu_to_le16(cmd_802_11_ps_mode); | ||
69 | cmd->size = | ||
70 | cpu_to_le16(sizeof(struct cmd_ds_802_11_ps_mode) + | ||
71 | S_DS_GEN); | ||
72 | psm->action = cpu_to_le16(cmd_action); | ||
73 | psm->multipledtim = 0; | ||
74 | switch (action) { | ||
75 | case cmd_subcmd_enter_ps: | ||
76 | lbs_pr_debug(1, "PS command:" "SubCode- Enter PS\n"); | ||
77 | lbs_pr_debug(1, "locallisteninterval = %d\n", | ||
78 | adapter->locallisteninterval); | ||
79 | |||
80 | psm->locallisteninterval = | ||
81 | cpu_to_le16(adapter->locallisteninterval); | ||
82 | psm->nullpktinterval = | ||
83 | cpu_to_le16(adapter->nullpktinterval); | ||
84 | psm->multipledtim = | ||
85 | cpu_to_le16(priv->adapter->multipledtim); | ||
86 | break; | ||
87 | |||
88 | case cmd_subcmd_exit_ps: | ||
89 | lbs_pr_debug(1, "PS command:" "SubCode- Exit PS\n"); | ||
90 | break; | ||
91 | |||
92 | case cmd_subcmd_sleep_confirmed: | ||
93 | lbs_pr_debug(1, "PS command: SubCode- sleep confirm\n"); | ||
94 | break; | ||
95 | |||
96 | default: | ||
97 | break; | ||
98 | } | ||
99 | |||
100 | LEAVE(); | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | static int wlan_cmd_802_11_inactivity_timeout(wlan_private * priv, | ||
105 | struct cmd_ds_command *cmd, | ||
106 | u16 cmd_action, void *pdata_buf) | ||
107 | { | ||
108 | u16 *timeout = pdata_buf; | ||
109 | |||
110 | cmd->command = cpu_to_le16(cmd_802_11_inactivity_timeout); | ||
111 | cmd->size = | ||
112 | cpu_to_le16(sizeof(struct cmd_ds_802_11_inactivity_timeout) | ||
113 | + S_DS_GEN); | ||
114 | |||
115 | cmd->params.inactivity_timeout.action = cpu_to_le16(cmd_action); | ||
116 | |||
117 | if (cmd_action) | ||
118 | cmd->params.inactivity_timeout.timeout = | ||
119 | cpu_to_le16(*timeout); | ||
120 | else | ||
121 | cmd->params.inactivity_timeout.timeout = 0; | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static int wlan_cmd_802_11_sleep_params(wlan_private * priv, | ||
127 | struct cmd_ds_command *cmd, | ||
128 | u16 cmd_action) | ||
129 | { | ||
130 | wlan_adapter *adapter = priv->adapter; | ||
131 | struct cmd_ds_802_11_sleep_params *sp = &cmd->params.sleep_params; | ||
132 | |||
133 | ENTER(); | ||
134 | |||
135 | cmd->size = | ||
136 | cpu_to_le16((sizeof(struct cmd_ds_802_11_sleep_params)) + | ||
137 | S_DS_GEN); | ||
138 | cmd->command = cpu_to_le16(cmd_802_11_sleep_params); | ||
139 | |||
140 | if (cmd_action == cmd_act_get) { | ||
141 | memset(&adapter->sp, 0, sizeof(struct sleep_params)); | ||
142 | memset(sp, 0, sizeof(struct cmd_ds_802_11_sleep_params)); | ||
143 | sp->action = cpu_to_le16(cmd_action); | ||
144 | } else if (cmd_action == cmd_act_set) { | ||
145 | sp->action = cpu_to_le16(cmd_action); | ||
146 | sp->error = cpu_to_le16(adapter->sp.sp_error); | ||
147 | sp->offset = cpu_to_le16(adapter->sp.sp_offset); | ||
148 | sp->stabletime = cpu_to_le16(adapter->sp.sp_stabletime); | ||
149 | sp->calcontrol = (u8) adapter->sp.sp_calcontrol; | ||
150 | sp->externalsleepclk = (u8) adapter->sp.sp_extsleepclk; | ||
151 | sp->reserved = cpu_to_le16(adapter->sp.sp_reserved); | ||
152 | } | ||
153 | |||
154 | LEAVE(); | ||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int wlan_cmd_802_11_set_wep(wlan_private * priv, | ||
159 | struct cmd_ds_command *cmd, | ||
160 | u32 cmd_act, | ||
161 | void * pdata_buf) | ||
162 | { | ||
163 | struct cmd_ds_802_11_set_wep *wep = &cmd->params.wep; | ||
164 | wlan_adapter *adapter = priv->adapter; | ||
165 | int ret = 0; | ||
166 | struct assoc_request * assoc_req = pdata_buf; | ||
167 | |||
168 | ENTER(); | ||
169 | |||
170 | cmd->command = cpu_to_le16(cmd_802_11_set_wep); | ||
171 | cmd->size = cpu_to_le16((sizeof(struct cmd_ds_802_11_set_wep)) | ||
172 | + S_DS_GEN); | ||
173 | |||
174 | if (cmd_act == cmd_act_add) { | ||
175 | int i; | ||
176 | |||
177 | if (!assoc_req) { | ||
178 | lbs_pr_debug(1, "Invalid association request!"); | ||
179 | ret = -1; | ||
180 | goto done; | ||
181 | } | ||
182 | |||
183 | wep->action = cpu_to_le16(cmd_act_add); | ||
184 | |||
185 | /* default tx key index */ | ||
186 | wep->keyindex = cpu_to_le16((u16) | ||
187 | (assoc_req->wep_tx_keyidx & | ||
188 | (u32)cmd_WEP_KEY_INDEX_MASK)); | ||
189 | |||
190 | lbs_pr_debug(1, "Tx key Index: %u\n", wep->keyindex); | ||
191 | |||
192 | /* Copy key types and material to host command structure */ | ||
193 | for (i = 0; i < 4; i++) { | ||
194 | struct WLAN_802_11_KEY * pkey = &assoc_req->wep_keys[i]; | ||
195 | |||
196 | switch (pkey->len) { | ||
197 | case KEY_LEN_WEP_40: | ||
198 | wep->keytype[i] = cmd_type_wep_40_bit; | ||
199 | memmove(&wep->keymaterial[i], pkey->key, | ||
200 | pkey->len); | ||
201 | break; | ||
202 | case KEY_LEN_WEP_104: | ||
203 | wep->keytype[i] = cmd_type_wep_104_bit; | ||
204 | memmove(&wep->keymaterial[i], pkey->key, | ||
205 | pkey->len); | ||
206 | break; | ||
207 | case 0: | ||
208 | break; | ||
209 | default: | ||
210 | lbs_pr_debug(1, "Invalid WEP key %d length of %d\n", | ||
211 | i, pkey->len); | ||
212 | ret = -1; | ||
213 | goto done; | ||
214 | break; | ||
215 | } | ||
216 | } | ||
217 | } else if (cmd_act == cmd_act_remove) { | ||
218 | /* ACT_REMOVE clears _all_ WEP keys */ | ||
219 | wep->action = cpu_to_le16(cmd_act_remove); | ||
220 | |||
221 | /* default tx key index */ | ||
222 | wep->keyindex = cpu_to_le16((u16) | ||
223 | (adapter->wep_tx_keyidx & | ||
224 | (u32)cmd_WEP_KEY_INDEX_MASK)); | ||
225 | } | ||
226 | |||
227 | ret = 0; | ||
228 | |||
229 | done: | ||
230 | LEAVE(); | ||
231 | return ret; | ||
232 | } | ||
233 | |||
234 | static int wlan_cmd_802_11_enable_rsn(wlan_private * priv, | ||
235 | struct cmd_ds_command *cmd, | ||
236 | u16 cmd_action) | ||
237 | { | ||
238 | struct cmd_ds_802_11_enable_rsn *penableRSN = &cmd->params.enbrsn; | ||
239 | wlan_adapter *adapter = priv->adapter; | ||
240 | |||
241 | cmd->command = cpu_to_le16(cmd_802_11_enable_rsn); | ||
242 | cmd->size = | ||
243 | cpu_to_le16(sizeof(struct cmd_ds_802_11_enable_rsn) + | ||
244 | S_DS_GEN); | ||
245 | penableRSN->action = cpu_to_le16(cmd_action); | ||
246 | if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { | ||
247 | penableRSN->enable = cpu_to_le16(cmd_enable_rsn); | ||
248 | } else { | ||
249 | penableRSN->enable = cpu_to_le16(cmd_disable_rsn); | ||
250 | } | ||
251 | |||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | |||
256 | static void set_one_wpa_key(struct MrvlIEtype_keyParamSet * pkeyparamset, | ||
257 | struct WLAN_802_11_KEY * pkey) | ||
258 | { | ||
259 | pkeyparamset->keytypeid = cpu_to_le16(pkey->type); | ||
260 | |||
261 | if (pkey->flags & KEY_INFO_WPA_ENABLED) { | ||
262 | pkeyparamset->keyinfo = cpu_to_le16(KEY_INFO_WPA_ENABLED); | ||
263 | } else { | ||
264 | pkeyparamset->keyinfo = cpu_to_le16(!KEY_INFO_WPA_ENABLED); | ||
265 | } | ||
266 | |||
267 | if (pkey->flags & KEY_INFO_WPA_UNICAST) { | ||
268 | pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_UNICAST); | ||
269 | } else if (pkey->flags & KEY_INFO_WPA_MCAST) { | ||
270 | pkeyparamset->keyinfo |= cpu_to_le16(KEY_INFO_WPA_MCAST); | ||
271 | } | ||
272 | |||
273 | pkeyparamset->type = cpu_to_le16(TLV_TYPE_KEY_MATERIAL); | ||
274 | pkeyparamset->keylen = cpu_to_le16(pkey->len); | ||
275 | memcpy(pkeyparamset->key, pkey->key, pkey->len); | ||
276 | pkeyparamset->length = cpu_to_le16( sizeof(pkeyparamset->keytypeid) | ||
277 | + sizeof(pkeyparamset->keyinfo) | ||
278 | + sizeof(pkeyparamset->keylen) | ||
279 | + sizeof(pkeyparamset->key)); | ||
280 | } | ||
281 | |||
282 | static int wlan_cmd_802_11_key_material(wlan_private * priv, | ||
283 | struct cmd_ds_command *cmd, | ||
284 | u16 cmd_action, | ||
285 | u32 cmd_oid, void *pdata_buf) | ||
286 | { | ||
287 | wlan_adapter *adapter = priv->adapter; | ||
288 | struct cmd_ds_802_11_key_material *pkeymaterial = | ||
289 | &cmd->params.keymaterial; | ||
290 | int ret = 0; | ||
291 | int index = 0; | ||
292 | |||
293 | ENTER(); | ||
294 | |||
295 | cmd->command = cpu_to_le16(cmd_802_11_key_material); | ||
296 | pkeymaterial->action = cpu_to_le16(cmd_action); | ||
297 | |||
298 | if (cmd_action == cmd_act_get) { | ||
299 | cmd->size = cpu_to_le16( S_DS_GEN | ||
300 | + sizeof (pkeymaterial->action)); | ||
301 | ret = 0; | ||
302 | goto done; | ||
303 | } | ||
304 | |||
305 | memset(&pkeymaterial->keyParamSet, 0, sizeof(pkeymaterial->keyParamSet)); | ||
306 | |||
307 | if (adapter->wpa_unicast_key.len) { | ||
308 | set_one_wpa_key(&pkeymaterial->keyParamSet[index], | ||
309 | &adapter->wpa_unicast_key); | ||
310 | index++; | ||
311 | } | ||
312 | |||
313 | if (adapter->wpa_mcast_key.len) { | ||
314 | set_one_wpa_key(&pkeymaterial->keyParamSet[index], | ||
315 | &adapter->wpa_mcast_key); | ||
316 | index++; | ||
317 | } | ||
318 | |||
319 | cmd->size = cpu_to_le16( S_DS_GEN | ||
320 | + sizeof (pkeymaterial->action) | ||
321 | + index * sizeof(struct MrvlIEtype_keyParamSet)); | ||
322 | |||
323 | ret = 0; | ||
324 | |||
325 | done: | ||
326 | LEAVE(); | ||
327 | return ret; | ||
328 | } | ||
329 | |||
330 | static int wlan_cmd_802_11_reset(wlan_private * priv, | ||
331 | struct cmd_ds_command *cmd, int cmd_action) | ||
332 | { | ||
333 | struct cmd_ds_802_11_reset *reset = &cmd->params.reset; | ||
334 | |||
335 | cmd->command = cpu_to_le16(cmd_802_11_reset); | ||
336 | cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_reset) + S_DS_GEN); | ||
337 | reset->action = cpu_to_le16(cmd_action); | ||
338 | |||
339 | return 0; | ||
340 | } | ||
341 | |||
342 | static int wlan_cmd_802_11_get_log(wlan_private * priv, | ||
343 | struct cmd_ds_command *cmd) | ||
344 | { | ||
345 | cmd->command = cpu_to_le16(cmd_802_11_get_log); | ||
346 | cmd->size = | ||
347 | cpu_to_le16(sizeof(struct cmd_ds_802_11_get_log) + S_DS_GEN); | ||
348 | |||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | static int wlan_cmd_802_11_get_stat(wlan_private * priv, | ||
353 | struct cmd_ds_command *cmd) | ||
354 | { | ||
355 | cmd->command = cpu_to_le16(cmd_802_11_get_stat); | ||
356 | cmd->size = | ||
357 | cpu_to_le16(sizeof(struct cmd_ds_802_11_get_stat) + | ||
358 | S_DS_GEN); | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | |||
363 | static int wlan_cmd_802_11_snmp_mib(wlan_private * priv, | ||
364 | struct cmd_ds_command *cmd, | ||
365 | int cmd_action, | ||
366 | int cmd_oid, void *pdata_buf) | ||
367 | { | ||
368 | struct cmd_ds_802_11_snmp_mib *pSNMPMIB = &cmd->params.smib; | ||
369 | wlan_adapter *adapter = priv->adapter; | ||
370 | u8 ucTemp; | ||
371 | |||
372 | ENTER(); | ||
373 | |||
374 | lbs_pr_debug(1, "SNMP_CMD: cmd_oid = 0x%x\n", cmd_oid); | ||
375 | |||
376 | cmd->command = cpu_to_le16(cmd_802_11_snmp_mib); | ||
377 | cmd->size = | ||
378 | cpu_to_le16(sizeof(struct cmd_ds_802_11_snmp_mib) + | ||
379 | S_DS_GEN); | ||
380 | |||
381 | switch (cmd_oid) { | ||
382 | case OID_802_11_INFRASTRUCTURE_MODE: | ||
383 | { | ||
384 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode = | ||
385 | (enum WLAN_802_11_NETWORK_INFRASTRUCTURE) pdata_buf; | ||
386 | pSNMPMIB->querytype = cpu_to_le16(cmd_act_set); | ||
387 | pSNMPMIB->oid = cpu_to_le16((u16) desired_bsstype_i); | ||
388 | pSNMPMIB->bufsize = sizeof(u8); | ||
389 | if (mode == wlan802_11infrastructure) | ||
390 | ucTemp = SNMP_MIB_VALUE_INFRA; | ||
391 | else | ||
392 | ucTemp = SNMP_MIB_VALUE_ADHOC; | ||
393 | |||
394 | memmove(pSNMPMIB->value, &ucTemp, sizeof(u8)); | ||
395 | |||
396 | break; | ||
397 | } | ||
398 | |||
399 | case OID_802_11D_ENABLE: | ||
400 | { | ||
401 | u32 ulTemp; | ||
402 | |||
403 | pSNMPMIB->oid = cpu_to_le16((u16) dot11d_i); | ||
404 | |||
405 | if (cmd_action == cmd_act_set) { | ||
406 | pSNMPMIB->querytype = cmd_act_set; | ||
407 | pSNMPMIB->bufsize = sizeof(u16); | ||
408 | ulTemp = *(u32 *)pdata_buf; | ||
409 | *((unsigned short *)(pSNMPMIB->value)) = | ||
410 | cpu_to_le16((u16) ulTemp); | ||
411 | } | ||
412 | break; | ||
413 | } | ||
414 | |||
415 | case OID_802_11_FRAGMENTATION_THRESHOLD: | ||
416 | { | ||
417 | u32 ulTemp; | ||
418 | |||
419 | pSNMPMIB->oid = cpu_to_le16((u16) fragthresh_i); | ||
420 | |||
421 | if (cmd_action == cmd_act_get) { | ||
422 | pSNMPMIB->querytype = | ||
423 | cpu_to_le16(cmd_act_get); | ||
424 | } else if (cmd_action == cmd_act_set) { | ||
425 | pSNMPMIB->querytype = | ||
426 | cpu_to_le16(cmd_act_set); | ||
427 | pSNMPMIB->bufsize = | ||
428 | cpu_to_le16(sizeof(u16)); | ||
429 | ulTemp = *((u32 *) pdata_buf); | ||
430 | *((unsigned short *)(pSNMPMIB->value)) = | ||
431 | cpu_to_le16((u16) ulTemp); | ||
432 | |||
433 | } | ||
434 | |||
435 | break; | ||
436 | } | ||
437 | |||
438 | case OID_802_11_RTS_THRESHOLD: | ||
439 | { | ||
440 | |||
441 | u32 ulTemp; | ||
442 | pSNMPMIB->oid = le16_to_cpu((u16) rtsthresh_i); | ||
443 | |||
444 | if (cmd_action == cmd_act_get) { | ||
445 | pSNMPMIB->querytype = | ||
446 | cpu_to_le16(cmd_act_get); | ||
447 | } else if (cmd_action == cmd_act_set) { | ||
448 | pSNMPMIB->querytype = | ||
449 | cpu_to_le16(cmd_act_set); | ||
450 | pSNMPMIB->bufsize = | ||
451 | cpu_to_le16(sizeof(u16)); | ||
452 | ulTemp = *((u32 *) | ||
453 | pdata_buf); | ||
454 | *(unsigned short *)(pSNMPMIB->value) = | ||
455 | cpu_to_le16((u16) ulTemp); | ||
456 | |||
457 | } | ||
458 | break; | ||
459 | } | ||
460 | case OID_802_11_TX_RETRYCOUNT: | ||
461 | pSNMPMIB->oid = cpu_to_le16((u16) short_retrylim_i); | ||
462 | |||
463 | if (cmd_action == cmd_act_get) { | ||
464 | pSNMPMIB->querytype = | ||
465 | cpu_to_le16(cmd_act_get); | ||
466 | } else if (cmd_action == cmd_act_set) { | ||
467 | pSNMPMIB->querytype = | ||
468 | cpu_to_le16(cmd_act_set); | ||
469 | pSNMPMIB->bufsize = cpu_to_le16(sizeof(u16)); | ||
470 | *((unsigned short *)(pSNMPMIB->value)) = | ||
471 | cpu_to_le16((u16) adapter->txretrycount); | ||
472 | } | ||
473 | |||
474 | break; | ||
475 | default: | ||
476 | break; | ||
477 | } | ||
478 | |||
479 | lbs_pr_debug(1, | ||
480 | "SNMP_CMD: command=0x%x, size=0x%x, seqnum=0x%x, result=0x%x\n", | ||
481 | cmd->command, cmd->size, cmd->seqnum, cmd->result); | ||
482 | |||
483 | lbs_pr_debug(1, | ||
484 | "SNMP_CMD: action=0x%x, oid=0x%x, oidsize=0x%x, value=0x%x\n", | ||
485 | pSNMPMIB->querytype, pSNMPMIB->oid, pSNMPMIB->bufsize, | ||
486 | *(u16 *) pSNMPMIB->value); | ||
487 | |||
488 | LEAVE(); | ||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | static int wlan_cmd_802_11_radio_control(wlan_private * priv, | ||
493 | struct cmd_ds_command *cmd, | ||
494 | int cmd_action) | ||
495 | { | ||
496 | wlan_adapter *adapter = priv->adapter; | ||
497 | struct cmd_ds_802_11_radio_control *pradiocontrol = | ||
498 | &cmd->params.radio; | ||
499 | |||
500 | ENTER(); | ||
501 | |||
502 | cmd->size = | ||
503 | cpu_to_le16((sizeof(struct cmd_ds_802_11_radio_control)) + | ||
504 | S_DS_GEN); | ||
505 | cmd->command = cpu_to_le16(cmd_802_11_radio_control); | ||
506 | |||
507 | pradiocontrol->action = cpu_to_le16(cmd_action); | ||
508 | |||
509 | switch (adapter->preamble) { | ||
510 | case cmd_type_short_preamble: | ||
511 | pradiocontrol->control = cpu_to_le16(SET_SHORT_PREAMBLE); | ||
512 | break; | ||
513 | |||
514 | case cmd_type_long_preamble: | ||
515 | pradiocontrol->control = cpu_to_le16(SET_LONG_PREAMBLE); | ||
516 | break; | ||
517 | |||
518 | case cmd_type_auto_preamble: | ||
519 | default: | ||
520 | pradiocontrol->control = cpu_to_le16(SET_AUTO_PREAMBLE); | ||
521 | break; | ||
522 | } | ||
523 | |||
524 | if (adapter->radioon) | ||
525 | pradiocontrol->control |= cpu_to_le16(TURN_ON_RF); | ||
526 | else | ||
527 | pradiocontrol->control &= cpu_to_le16(~TURN_ON_RF); | ||
528 | |||
529 | LEAVE(); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int wlan_cmd_802_11_rf_tx_power(wlan_private * priv, | ||
534 | struct cmd_ds_command *cmd, | ||
535 | u16 cmd_action, void *pdata_buf) | ||
536 | { | ||
537 | |||
538 | struct cmd_ds_802_11_rf_tx_power *prtp = &cmd->params.txp; | ||
539 | |||
540 | ENTER(); | ||
541 | |||
542 | cmd->size = | ||
543 | cpu_to_le16((sizeof(struct cmd_ds_802_11_rf_tx_power)) + | ||
544 | S_DS_GEN); | ||
545 | cmd->command = cpu_to_le16(cmd_802_11_rf_tx_power); | ||
546 | prtp->action = cmd_action; | ||
547 | |||
548 | lbs_pr_debug(1, "RF_TX_POWER_CMD: size:%d cmd:0x%x Act:%d\n", cmd->size, | ||
549 | cmd->command, prtp->action); | ||
550 | |||
551 | switch (cmd_action) { | ||
552 | case cmd_act_tx_power_opt_get: | ||
553 | prtp->action = cpu_to_le16(cmd_act_get); | ||
554 | prtp->currentlevel = 0; | ||
555 | break; | ||
556 | |||
557 | case cmd_act_tx_power_opt_set_high: | ||
558 | prtp->action = cpu_to_le16(cmd_act_set); | ||
559 | prtp->currentlevel = | ||
560 | cpu_to_le16(cmd_act_tx_power_index_high); | ||
561 | break; | ||
562 | |||
563 | case cmd_act_tx_power_opt_set_mid: | ||
564 | prtp->action = cpu_to_le16(cmd_act_set); | ||
565 | prtp->currentlevel = | ||
566 | cpu_to_le16(cmd_act_tx_power_index_mid); | ||
567 | break; | ||
568 | |||
569 | case cmd_act_tx_power_opt_set_low: | ||
570 | prtp->action = cpu_to_le16(cmd_act_set); | ||
571 | prtp->currentlevel = cpu_to_le16(*((u16 *) pdata_buf)); | ||
572 | break; | ||
573 | } | ||
574 | LEAVE(); | ||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | static int wlan_cmd_802_11_rf_antenna(wlan_private * priv, | ||
579 | struct cmd_ds_command *cmd, | ||
580 | u16 cmd_action, void *pdata_buf) | ||
581 | { | ||
582 | struct cmd_ds_802_11_rf_antenna *rant = &cmd->params.rant; | ||
583 | |||
584 | cmd->command = cpu_to_le16(cmd_802_11_rf_antenna); | ||
585 | cmd->size = | ||
586 | cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_antenna) + | ||
587 | S_DS_GEN); | ||
588 | |||
589 | rant->action = cpu_to_le16(cmd_action); | ||
590 | if ((cmd_action == cmd_act_set_rx) || | ||
591 | (cmd_action == cmd_act_set_tx)) { | ||
592 | rant->antennamode = | ||
593 | cpu_to_le16((u16) (*(u32 *) pdata_buf)); | ||
594 | } | ||
595 | |||
596 | return 0; | ||
597 | } | ||
598 | |||
599 | static int wlan_cmd_802_11_rate_adapt_rateset(wlan_private * priv, | ||
600 | struct cmd_ds_command *cmd, | ||
601 | u16 cmd_action) | ||
602 | { | ||
603 | struct cmd_ds_802_11_rate_adapt_rateset | ||
604 | *rateadapt = &cmd->params.rateset; | ||
605 | wlan_adapter *adapter = priv->adapter; | ||
606 | |||
607 | cmd->size = | ||
608 | cpu_to_le16(sizeof(struct cmd_ds_802_11_rate_adapt_rateset) | ||
609 | + S_DS_GEN); | ||
610 | cmd->command = cpu_to_le16(cmd_802_11_rate_adapt_rateset); | ||
611 | |||
612 | ENTER(); | ||
613 | |||
614 | rateadapt->action = cmd_action; | ||
615 | rateadapt->enablehwauto = adapter->enablehwauto; | ||
616 | rateadapt->bitmap = adapter->ratebitmap; | ||
617 | |||
618 | LEAVE(); | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int wlan_cmd_802_11_data_rate(wlan_private * priv, | ||
623 | struct cmd_ds_command *cmd, | ||
624 | u16 cmd_action) | ||
625 | { | ||
626 | struct cmd_ds_802_11_data_rate *pdatarate = &cmd->params.drate; | ||
627 | wlan_adapter *adapter = priv->adapter; | ||
628 | u16 action = cmd_action; | ||
629 | |||
630 | ENTER(); | ||
631 | |||
632 | cmd->size = | ||
633 | cpu_to_le16(sizeof(struct cmd_ds_802_11_data_rate) + | ||
634 | S_DS_GEN); | ||
635 | |||
636 | cmd->command = cpu_to_le16(cmd_802_11_data_rate); | ||
637 | |||
638 | memset(pdatarate, 0, sizeof(struct cmd_ds_802_11_data_rate)); | ||
639 | |||
640 | pdatarate->action = cpu_to_le16(cmd_action); | ||
641 | |||
642 | if (action == cmd_act_set_tx_fix_rate) { | ||
643 | pdatarate->datarate[0] = libertas_data_rate_to_index(adapter->datarate); | ||
644 | lbs_pr_debug(1, "Setting FW for fixed rate 0x%02X\n", | ||
645 | adapter->datarate); | ||
646 | } else if (action == cmd_act_set_tx_auto) { | ||
647 | lbs_pr_debug(1, "Setting FW for AUTO rate\n"); | ||
648 | } | ||
649 | |||
650 | LEAVE(); | ||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static int wlan_cmd_mac_multicast_adr(wlan_private * priv, | ||
655 | struct cmd_ds_command *cmd, | ||
656 | u16 cmd_action) | ||
657 | { | ||
658 | struct cmd_ds_mac_multicast_adr *pMCastAdr = &cmd->params.madr; | ||
659 | wlan_adapter *adapter = priv->adapter; | ||
660 | |||
661 | cmd->size = | ||
662 | cpu_to_le16(sizeof(struct cmd_ds_mac_multicast_adr) + | ||
663 | S_DS_GEN); | ||
664 | cmd->command = cpu_to_le16(cmd_mac_multicast_adr); | ||
665 | |||
666 | pMCastAdr->action = cpu_to_le16(cmd_action); | ||
667 | pMCastAdr->nr_of_adrs = | ||
668 | cpu_to_le16((u16) adapter->nr_of_multicastmacaddr); | ||
669 | memcpy(pMCastAdr->maclist, adapter->multicastlist, | ||
670 | adapter->nr_of_multicastmacaddr * ETH_ALEN); | ||
671 | |||
672 | return 0; | ||
673 | } | ||
674 | |||
675 | static int wlan_cmd_802_11_rf_channel(wlan_private * priv, | ||
676 | struct cmd_ds_command *cmd, | ||
677 | int option, void *pdata_buf) | ||
678 | { | ||
679 | struct cmd_ds_802_11_rf_channel *rfchan = &cmd->params.rfchannel; | ||
680 | |||
681 | cmd->command = cpu_to_le16(cmd_802_11_rf_channel); | ||
682 | cmd->size = cpu_to_le16(sizeof(struct cmd_ds_802_11_rf_channel) | ||
683 | + S_DS_GEN); | ||
684 | |||
685 | if (option == cmd_opt_802_11_rf_channel_set) { | ||
686 | rfchan->currentchannel = cpu_to_le16(*((u16 *) pdata_buf)); | ||
687 | } | ||
688 | |||
689 | rfchan->action = cpu_to_le16(option); | ||
690 | |||
691 | return 0; | ||
692 | } | ||
693 | |||
694 | static int wlan_cmd_802_11_rssi(wlan_private * priv, | ||
695 | struct cmd_ds_command *cmd) | ||
696 | { | ||
697 | wlan_adapter *adapter = priv->adapter; | ||
698 | |||
699 | cmd->command = cpu_to_le16(cmd_802_11_rssi); | ||
700 | cmd->size = | ||
701 | cpu_to_le16(sizeof(struct cmd_ds_802_11_rssi) + S_DS_GEN); | ||
702 | cmd->params.rssi.N = priv->adapter->bcn_avg_factor; | ||
703 | |||
704 | /* reset Beacon SNR/NF/RSSI values */ | ||
705 | adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = 0; | ||
706 | adapter->SNR[TYPE_BEACON][TYPE_AVG] = 0; | ||
707 | adapter->NF[TYPE_BEACON][TYPE_NOAVG] = 0; | ||
708 | adapter->NF[TYPE_BEACON][TYPE_AVG] = 0; | ||
709 | adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = 0; | ||
710 | adapter->RSSI[TYPE_BEACON][TYPE_AVG] = 0; | ||
711 | |||
712 | return 0; | ||
713 | } | ||
714 | |||
715 | static int wlan_cmd_reg_access(wlan_private * priv, | ||
716 | struct cmd_ds_command *cmdptr, | ||
717 | u8 cmd_action, void *pdata_buf) | ||
718 | { | ||
719 | struct wlan_offset_value *offval; | ||
720 | |||
721 | ENTER(); | ||
722 | |||
723 | offval = (struct wlan_offset_value *)pdata_buf; | ||
724 | |||
725 | switch (cmdptr->command) { | ||
726 | case cmd_mac_reg_access: | ||
727 | { | ||
728 | struct cmd_ds_mac_reg_access *macreg; | ||
729 | |||
730 | cmdptr->size = | ||
731 | cpu_to_le16(sizeof | ||
732 | (struct cmd_ds_mac_reg_access) | ||
733 | + S_DS_GEN); | ||
734 | macreg = | ||
735 | (struct cmd_ds_mac_reg_access *)&cmdptr->params. | ||
736 | macreg; | ||
737 | |||
738 | macreg->action = cpu_to_le16(cmd_action); | ||
739 | macreg->offset = cpu_to_le16((u16) offval->offset); | ||
740 | macreg->value = cpu_to_le32(offval->value); | ||
741 | |||
742 | break; | ||
743 | } | ||
744 | |||
745 | case cmd_bbp_reg_access: | ||
746 | { | ||
747 | struct cmd_ds_bbp_reg_access *bbpreg; | ||
748 | |||
749 | cmdptr->size = | ||
750 | cpu_to_le16(sizeof | ||
751 | (struct cmd_ds_bbp_reg_access) | ||
752 | + S_DS_GEN); | ||
753 | bbpreg = | ||
754 | (struct cmd_ds_bbp_reg_access *)&cmdptr->params. | ||
755 | bbpreg; | ||
756 | |||
757 | bbpreg->action = cpu_to_le16(cmd_action); | ||
758 | bbpreg->offset = cpu_to_le16((u16) offval->offset); | ||
759 | bbpreg->value = (u8) offval->value; | ||
760 | |||
761 | break; | ||
762 | } | ||
763 | |||
764 | case cmd_rf_reg_access: | ||
765 | { | ||
766 | struct cmd_ds_rf_reg_access *rfreg; | ||
767 | |||
768 | cmdptr->size = | ||
769 | cpu_to_le16(sizeof | ||
770 | (struct cmd_ds_rf_reg_access) + | ||
771 | S_DS_GEN); | ||
772 | rfreg = | ||
773 | (struct cmd_ds_rf_reg_access *)&cmdptr->params. | ||
774 | rfreg; | ||
775 | |||
776 | rfreg->action = cpu_to_le16(cmd_action); | ||
777 | rfreg->offset = cpu_to_le16((u16) offval->offset); | ||
778 | rfreg->value = (u8) offval->value; | ||
779 | |||
780 | break; | ||
781 | } | ||
782 | |||
783 | default: | ||
784 | break; | ||
785 | } | ||
786 | |||
787 | LEAVE(); | ||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | static int wlan_cmd_802_11_mac_address(wlan_private * priv, | ||
792 | struct cmd_ds_command *cmd, | ||
793 | u16 cmd_action) | ||
794 | { | ||
795 | wlan_adapter *adapter = priv->adapter; | ||
796 | |||
797 | cmd->command = cpu_to_le16(cmd_802_11_mac_address); | ||
798 | cmd->size = | ||
799 | cpu_to_le16(sizeof(struct cmd_ds_802_11_mac_address) + | ||
800 | S_DS_GEN); | ||
801 | cmd->result = 0; | ||
802 | |||
803 | cmd->params.macadd.action = cpu_to_le16(cmd_action); | ||
804 | |||
805 | if (cmd_action == cmd_act_set) { | ||
806 | memcpy(cmd->params.macadd.macadd, | ||
807 | adapter->current_addr, ETH_ALEN); | ||
808 | lbs_dbg_hex("SET_CMD: MAC ADDRESS-", adapter->current_addr, 6); | ||
809 | } | ||
810 | |||
811 | return 0; | ||
812 | } | ||
813 | |||
814 | static int wlan_cmd_802_11_eeprom_access(wlan_private * priv, | ||
815 | struct cmd_ds_command *cmd, | ||
816 | int cmd_action, void *pdata_buf) | ||
817 | { | ||
818 | struct wlan_ioctl_regrdwr *ea = pdata_buf; | ||
819 | |||
820 | ENTER(); | ||
821 | |||
822 | cmd->command = cpu_to_le16(cmd_802_11_eeprom_access); | ||
823 | cmd->size = | ||
824 | cpu_to_le16(sizeof(struct cmd_ds_802_11_eeprom_access) + | ||
825 | S_DS_GEN); | ||
826 | cmd->result = 0; | ||
827 | |||
828 | cmd->params.rdeeprom.action = cpu_to_le16(ea->action); | ||
829 | cmd->params.rdeeprom.offset = cpu_to_le16(ea->offset); | ||
830 | cmd->params.rdeeprom.bytecount = cpu_to_le16(ea->NOB); | ||
831 | cmd->params.rdeeprom.value = 0; | ||
832 | |||
833 | return 0; | ||
834 | } | ||
835 | |||
836 | static int wlan_cmd_bt_access(wlan_private * priv, | ||
837 | struct cmd_ds_command *cmd, | ||
838 | u16 cmd_action, void *pdata_buf) | ||
839 | { | ||
840 | struct cmd_ds_bt_access *bt_access = &cmd->params.bt; | ||
841 | lbs_pr_debug(1, "BT CMD(%d)\n", cmd_action); | ||
842 | |||
843 | cmd->command = cpu_to_le16(cmd_bt_access); | ||
844 | cmd->size = cpu_to_le16(sizeof(struct cmd_ds_bt_access) | ||
845 | + S_DS_GEN); | ||
846 | cmd->result = 0; | ||
847 | bt_access->action = cpu_to_le16(cmd_action); | ||
848 | |||
849 | switch (cmd_action) { | ||
850 | case cmd_act_bt_access_add: | ||
851 | memcpy(bt_access->addr1, pdata_buf, 2 * ETH_ALEN); | ||
852 | lbs_dbg_hex("BT_ADD: blinded mac address-", bt_access->addr1, 6); | ||
853 | break; | ||
854 | case cmd_act_bt_access_del: | ||
855 | memcpy(bt_access->addr1, pdata_buf, 1 * ETH_ALEN); | ||
856 | lbs_dbg_hex("BT_DEL: blinded mac address-", bt_access->addr1, 6); | ||
857 | break; | ||
858 | case cmd_act_bt_access_list: | ||
859 | bt_access->id = cpu_to_le32(*(u32 *) pdata_buf); | ||
860 | break; | ||
861 | case cmd_act_bt_access_reset: | ||
862 | break; | ||
863 | default: | ||
864 | break; | ||
865 | } | ||
866 | return 0; | ||
867 | } | ||
868 | |||
869 | static int wlan_cmd_fwt_access(wlan_private * priv, | ||
870 | struct cmd_ds_command *cmd, | ||
871 | u16 cmd_action, void *pdata_buf) | ||
872 | { | ||
873 | struct cmd_ds_fwt_access *fwt_access = &cmd->params.fwt; | ||
874 | lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action); | ||
875 | |||
876 | cmd->command = cpu_to_le16(cmd_fwt_access); | ||
877 | cmd->size = cpu_to_le16(sizeof(struct cmd_ds_fwt_access) | ||
878 | + S_DS_GEN); | ||
879 | cmd->result = 0; | ||
880 | |||
881 | if (pdata_buf) | ||
882 | memcpy(fwt_access, pdata_buf, sizeof(*fwt_access)); | ||
883 | else | ||
884 | memset(fwt_access, 0, sizeof(*fwt_access)); | ||
885 | |||
886 | fwt_access->action = cpu_to_le16(cmd_action); | ||
887 | |||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static int wlan_cmd_mesh_access(wlan_private * priv, | ||
892 | struct cmd_ds_command *cmd, | ||
893 | u16 cmd_action, void *pdata_buf) | ||
894 | { | ||
895 | struct cmd_ds_mesh_access *mesh_access = &cmd->params.mesh; | ||
896 | lbs_pr_debug(1, "FWT CMD(%d)\n", cmd_action); | ||
897 | |||
898 | cmd->command = cpu_to_le16(cmd_mesh_access); | ||
899 | cmd->size = cpu_to_le16(sizeof(struct cmd_ds_mesh_access) | ||
900 | + S_DS_GEN); | ||
901 | cmd->result = 0; | ||
902 | |||
903 | if (pdata_buf) | ||
904 | memcpy(mesh_access, pdata_buf, sizeof(*mesh_access)); | ||
905 | else | ||
906 | memset(mesh_access, 0, sizeof(*mesh_access)); | ||
907 | |||
908 | mesh_access->action = cpu_to_le16(cmd_action); | ||
909 | |||
910 | return 0; | ||
911 | } | ||
912 | |||
913 | void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail) | ||
914 | { | ||
915 | unsigned long flags; | ||
916 | struct cmd_ds_command *cmdptr; | ||
917 | |||
918 | ENTER(); | ||
919 | |||
920 | if (!cmdnode) { | ||
921 | lbs_pr_debug(1, "QUEUE_CMD: cmdnode is NULL\n"); | ||
922 | goto done; | ||
923 | } | ||
924 | |||
925 | cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; | ||
926 | if (!cmdptr) { | ||
927 | lbs_pr_debug(1, "QUEUE_CMD: cmdptr is NULL\n"); | ||
928 | goto done; | ||
929 | } | ||
930 | |||
931 | /* Exit_PS command needs to be queued in the header always. */ | ||
932 | if (cmdptr->command == cmd_802_11_ps_mode) { | ||
933 | struct cmd_ds_802_11_ps_mode *psm = &cmdptr->params.psmode; | ||
934 | if (psm->action == cmd_subcmd_exit_ps) { | ||
935 | if (adapter->psstate != PS_STATE_FULL_POWER) | ||
936 | addtail = 0; | ||
937 | } | ||
938 | } | ||
939 | |||
940 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
941 | |||
942 | if (addtail) | ||
943 | list_add_tail((struct list_head *)cmdnode, | ||
944 | &adapter->cmdpendingq); | ||
945 | else | ||
946 | list_add((struct list_head *)cmdnode, &adapter->cmdpendingq); | ||
947 | |||
948 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
949 | |||
950 | lbs_pr_debug(1, "QUEUE_CMD: Inserted node=0x%x, cmd=0x%x in cmdpendingq\n", | ||
951 | (u32) cmdnode, | ||
952 | ((struct cmd_ds_gen*)cmdnode->bufvirtualaddr)->command); | ||
953 | |||
954 | done: | ||
955 | LEAVE(); | ||
956 | return; | ||
957 | } | ||
958 | |||
959 | /* | ||
960 | * TODO: Fix the issue when DownloadcommandToStation is being called the | ||
961 | * second time when the command timesout. All the cmdptr->xxx are in little | ||
962 | * endian and therefore all the comparissions will fail. | ||
963 | * For now - we are not performing the endian conversion the second time - but | ||
964 | * for PS and DEEP_SLEEP we need to worry | ||
965 | */ | ||
966 | static int DownloadcommandToStation(wlan_private * priv, | ||
967 | struct cmd_ctrl_node *cmdnode) | ||
968 | { | ||
969 | unsigned long flags; | ||
970 | struct cmd_ds_command *cmdptr; | ||
971 | wlan_adapter *adapter = priv->adapter; | ||
972 | int ret = 0; | ||
973 | u16 cmdsize; | ||
974 | u16 command; | ||
975 | |||
976 | ENTER(); | ||
977 | |||
978 | if (!adapter || !cmdnode) { | ||
979 | lbs_pr_debug(1, "DNLD_CMD: adapter = %#x, cmdnode = %#x\n", | ||
980 | (int)adapter, (int)cmdnode); | ||
981 | if (cmdnode) { | ||
982 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
983 | __libertas_cleanup_and_insert_cmd(priv, cmdnode); | ||
984 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
985 | } | ||
986 | ret = -1; | ||
987 | goto done; | ||
988 | } | ||
989 | |||
990 | cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; | ||
991 | |||
992 | |||
993 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
994 | if (!cmdptr || !cmdptr->size) { | ||
995 | lbs_pr_debug(1, "DNLD_CMD: cmdptr is Null or cmd size is Zero, " | ||
996 | "Not sending\n"); | ||
997 | __libertas_cleanup_and_insert_cmd(priv, cmdnode); | ||
998 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
999 | ret = -1; | ||
1000 | goto done; | ||
1001 | } | ||
1002 | |||
1003 | adapter->cur_cmd = cmdnode; | ||
1004 | adapter->cur_cmd_retcode = 0; | ||
1005 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1006 | lbs_pr_debug(1, "DNLD_CMD:: Before download, size of cmd = %d\n", | ||
1007 | cmdptr->size); | ||
1008 | |||
1009 | cmdsize = cmdptr->size; | ||
1010 | |||
1011 | command = cpu_to_le16(cmdptr->command); | ||
1012 | |||
1013 | cmdnode->cmdwaitqwoken = 0; | ||
1014 | cmdsize = cpu_to_le16(cmdsize); | ||
1015 | |||
1016 | ret = libertas_sbi_host_to_card(priv, MVMS_CMD, (u8 *) cmdptr, cmdsize); | ||
1017 | |||
1018 | if (ret != 0) { | ||
1019 | lbs_pr_debug(1, "DNLD_CMD: Host to Card failed\n"); | ||
1020 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
1021 | __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); | ||
1022 | adapter->cur_cmd = NULL; | ||
1023 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1024 | ret = -1; | ||
1025 | goto done; | ||
1026 | } | ||
1027 | |||
1028 | lbs_pr_debug(1, "DNLD_CMD: Sent command 0x%x @ %lu\n", command, jiffies); | ||
1029 | lbs_dbg_hex("DNLD_CMD: command", cmdnode->bufvirtualaddr, cmdsize); | ||
1030 | |||
1031 | /* Setup the timer after transmit command */ | ||
1032 | if (command == cmd_802_11_scan | ||
1033 | || command == cmd_802_11_authenticate | ||
1034 | || command == cmd_802_11_associate) | ||
1035 | mod_timer(&adapter->command_timer, jiffies + (10*HZ)); | ||
1036 | else | ||
1037 | mod_timer(&adapter->command_timer, jiffies + (5*HZ)); | ||
1038 | |||
1039 | ret = 0; | ||
1040 | |||
1041 | done: | ||
1042 | LEAVE(); | ||
1043 | return ret; | ||
1044 | } | ||
1045 | |||
1046 | static int wlan_cmd_mac_control(wlan_private * priv, | ||
1047 | struct cmd_ds_command *cmd) | ||
1048 | { | ||
1049 | struct cmd_ds_mac_control *mac = &cmd->params.macctrl; | ||
1050 | |||
1051 | ENTER(); | ||
1052 | |||
1053 | cmd->command = cpu_to_le16(cmd_mac_control); | ||
1054 | cmd->size = | ||
1055 | cpu_to_le16(sizeof(struct cmd_ds_mac_control) + S_DS_GEN); | ||
1056 | mac->action = cpu_to_le16(priv->adapter->currentpacketfilter); | ||
1057 | |||
1058 | lbs_pr_debug(1, "wlan_cmd_mac_control(): action=0x%X size=%d\n", | ||
1059 | mac->action, cmd->size); | ||
1060 | |||
1061 | LEAVE(); | ||
1062 | return 0; | ||
1063 | } | ||
1064 | |||
1065 | /** | ||
1066 | * This function inserts command node to cmdfreeq | ||
1067 | * after cleans it. Requires adapter->driver_lock held. | ||
1068 | */ | ||
1069 | void __libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) | ||
1070 | { | ||
1071 | wlan_adapter *adapter = priv->adapter; | ||
1072 | |||
1073 | if (!ptempcmd) | ||
1074 | goto done; | ||
1075 | |||
1076 | cleanup_cmdnode(ptempcmd); | ||
1077 | list_add_tail((struct list_head *)ptempcmd, &adapter->cmdfreeq); | ||
1078 | done: | ||
1079 | return; | ||
1080 | } | ||
1081 | |||
1082 | void libertas_cleanup_and_insert_cmd(wlan_private * priv, struct cmd_ctrl_node *ptempcmd) | ||
1083 | { | ||
1084 | unsigned long flags; | ||
1085 | |||
1086 | spin_lock_irqsave(&priv->adapter->driver_lock, flags); | ||
1087 | __libertas_cleanup_and_insert_cmd(priv, ptempcmd); | ||
1088 | spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); | ||
1089 | } | ||
1090 | |||
1091 | int libertas_set_radio_control(wlan_private * priv) | ||
1092 | { | ||
1093 | int ret = 0; | ||
1094 | |||
1095 | ENTER(); | ||
1096 | |||
1097 | ret = libertas_prepare_and_send_command(priv, | ||
1098 | cmd_802_11_radio_control, | ||
1099 | cmd_act_set, | ||
1100 | cmd_option_waitforrsp, 0, NULL); | ||
1101 | |||
1102 | lbs_pr_debug(1, "RADIO_SET: on or off: 0x%X, preamble = 0x%X\n", | ||
1103 | priv->adapter->radioon, priv->adapter->preamble); | ||
1104 | |||
1105 | LEAVE(); | ||
1106 | return ret; | ||
1107 | } | ||
1108 | |||
1109 | int libertas_set_mac_packet_filter(wlan_private * priv) | ||
1110 | { | ||
1111 | int ret = 0; | ||
1112 | |||
1113 | ENTER(); | ||
1114 | |||
1115 | lbs_pr_debug(1, "libertas_set_mac_packet_filter value = %x\n", | ||
1116 | priv->adapter->currentpacketfilter); | ||
1117 | |||
1118 | /* Send MAC control command to station */ | ||
1119 | ret = libertas_prepare_and_send_command(priv, | ||
1120 | cmd_mac_control, 0, 0, 0, NULL); | ||
1121 | |||
1122 | LEAVE(); | ||
1123 | return ret; | ||
1124 | } | ||
1125 | |||
1126 | /** | ||
1127 | * @brief This function prepare the command before send to firmware. | ||
1128 | * | ||
1129 | * @param priv A pointer to wlan_private structure | ||
1130 | * @param cmd_no command number | ||
1131 | * @param cmd_action command action: GET or SET | ||
1132 | * @param wait_option wait option: wait response or not | ||
1133 | * @param cmd_oid cmd oid: treated as sub command | ||
1134 | * @param pdata_buf A pointer to informaion buffer | ||
1135 | * @return 0 or -1 | ||
1136 | */ | ||
1137 | int libertas_prepare_and_send_command(wlan_private * priv, | ||
1138 | u16 cmd_no, | ||
1139 | u16 cmd_action, | ||
1140 | u16 wait_option, u32 cmd_oid, void *pdata_buf) | ||
1141 | { | ||
1142 | int ret = 0; | ||
1143 | wlan_adapter *adapter = priv->adapter; | ||
1144 | struct cmd_ctrl_node *cmdnode; | ||
1145 | struct cmd_ds_command *cmdptr; | ||
1146 | unsigned long flags; | ||
1147 | |||
1148 | ENTER(); | ||
1149 | |||
1150 | if (!adapter) { | ||
1151 | lbs_pr_debug(1, "PREP_CMD: adapter is Null\n"); | ||
1152 | ret = -1; | ||
1153 | goto done; | ||
1154 | } | ||
1155 | |||
1156 | if (adapter->surpriseremoved) { | ||
1157 | lbs_pr_debug(1, "PREP_CMD: Card is Removed\n"); | ||
1158 | ret = -1; | ||
1159 | goto done; | ||
1160 | } | ||
1161 | |||
1162 | cmdnode = libertas_get_free_cmd_ctrl_node(priv); | ||
1163 | |||
1164 | if (cmdnode == NULL) { | ||
1165 | lbs_pr_debug(1, "PREP_CMD: No free cmdnode\n"); | ||
1166 | |||
1167 | /* Wake up main thread to execute next command */ | ||
1168 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1169 | ret = -1; | ||
1170 | goto done; | ||
1171 | } | ||
1172 | |||
1173 | libertas_set_cmd_ctrl_node(priv, cmdnode, cmd_oid, wait_option, pdata_buf); | ||
1174 | |||
1175 | cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; | ||
1176 | |||
1177 | lbs_pr_debug(1, "PREP_CMD: Val of cmd ptr =0x%x, command=0x%X\n", | ||
1178 | (u32) cmdptr, cmd_no); | ||
1179 | |||
1180 | if (!cmdptr) { | ||
1181 | lbs_pr_debug(1, "PREP_CMD: bufvirtualaddr of cmdnode is NULL\n"); | ||
1182 | libertas_cleanup_and_insert_cmd(priv, cmdnode); | ||
1183 | ret = -1; | ||
1184 | goto done; | ||
1185 | } | ||
1186 | |||
1187 | /* Set sequence number, command and INT option */ | ||
1188 | adapter->seqnum++; | ||
1189 | cmdptr->seqnum = cpu_to_le16(adapter->seqnum); | ||
1190 | |||
1191 | cmdptr->command = cmd_no; | ||
1192 | cmdptr->result = 0; | ||
1193 | |||
1194 | switch (cmd_no) { | ||
1195 | case cmd_get_hw_spec: | ||
1196 | ret = wlan_cmd_hw_spec(priv, cmdptr); | ||
1197 | break; | ||
1198 | case cmd_802_11_ps_mode: | ||
1199 | ret = wlan_cmd_802_11_ps_mode(priv, cmdptr, cmd_action); | ||
1200 | break; | ||
1201 | |||
1202 | case cmd_802_11_scan: | ||
1203 | ret = libertas_cmd_80211_scan(priv, cmdptr, pdata_buf); | ||
1204 | break; | ||
1205 | |||
1206 | case cmd_mac_control: | ||
1207 | ret = wlan_cmd_mac_control(priv, cmdptr); | ||
1208 | break; | ||
1209 | |||
1210 | case cmd_802_11_associate: | ||
1211 | case cmd_802_11_reassociate: | ||
1212 | ret = libertas_cmd_80211_associate(priv, cmdptr, pdata_buf); | ||
1213 | break; | ||
1214 | |||
1215 | case cmd_802_11_deauthenticate: | ||
1216 | ret = libertas_cmd_80211_deauthenticate(priv, cmdptr); | ||
1217 | break; | ||
1218 | |||
1219 | case cmd_802_11_set_wep: | ||
1220 | ret = wlan_cmd_802_11_set_wep(priv, cmdptr, cmd_action, pdata_buf); | ||
1221 | break; | ||
1222 | |||
1223 | case cmd_802_11_ad_hoc_start: | ||
1224 | ret = libertas_cmd_80211_ad_hoc_start(priv, cmdptr, pdata_buf); | ||
1225 | break; | ||
1226 | case cmd_code_dnld: | ||
1227 | break; | ||
1228 | |||
1229 | case cmd_802_11_reset: | ||
1230 | ret = wlan_cmd_802_11_reset(priv, cmdptr, cmd_action); | ||
1231 | break; | ||
1232 | |||
1233 | case cmd_802_11_get_log: | ||
1234 | ret = wlan_cmd_802_11_get_log(priv, cmdptr); | ||
1235 | break; | ||
1236 | |||
1237 | case cmd_802_11_authenticate: | ||
1238 | ret = libertas_cmd_80211_authenticate(priv, cmdptr, pdata_buf); | ||
1239 | break; | ||
1240 | |||
1241 | case cmd_802_11_get_stat: | ||
1242 | ret = wlan_cmd_802_11_get_stat(priv, cmdptr); | ||
1243 | break; | ||
1244 | |||
1245 | case cmd_802_11_snmp_mib: | ||
1246 | ret = wlan_cmd_802_11_snmp_mib(priv, cmdptr, | ||
1247 | cmd_action, cmd_oid, pdata_buf); | ||
1248 | break; | ||
1249 | |||
1250 | case cmd_mac_reg_access: | ||
1251 | case cmd_bbp_reg_access: | ||
1252 | case cmd_rf_reg_access: | ||
1253 | ret = wlan_cmd_reg_access(priv, cmdptr, cmd_action, pdata_buf); | ||
1254 | break; | ||
1255 | |||
1256 | case cmd_802_11_rf_channel: | ||
1257 | ret = wlan_cmd_802_11_rf_channel(priv, cmdptr, | ||
1258 | cmd_action, pdata_buf); | ||
1259 | break; | ||
1260 | |||
1261 | case cmd_802_11_rf_tx_power: | ||
1262 | ret = wlan_cmd_802_11_rf_tx_power(priv, cmdptr, | ||
1263 | cmd_action, pdata_buf); | ||
1264 | break; | ||
1265 | |||
1266 | case cmd_802_11_radio_control: | ||
1267 | ret = wlan_cmd_802_11_radio_control(priv, cmdptr, cmd_action); | ||
1268 | break; | ||
1269 | |||
1270 | case cmd_802_11_rf_antenna: | ||
1271 | ret = wlan_cmd_802_11_rf_antenna(priv, cmdptr, | ||
1272 | cmd_action, pdata_buf); | ||
1273 | break; | ||
1274 | |||
1275 | case cmd_802_11_data_rate: | ||
1276 | ret = wlan_cmd_802_11_data_rate(priv, cmdptr, cmd_action); | ||
1277 | break; | ||
1278 | case cmd_802_11_rate_adapt_rateset: | ||
1279 | ret = wlan_cmd_802_11_rate_adapt_rateset(priv, | ||
1280 | cmdptr, cmd_action); | ||
1281 | break; | ||
1282 | |||
1283 | case cmd_mac_multicast_adr: | ||
1284 | ret = wlan_cmd_mac_multicast_adr(priv, cmdptr, cmd_action); | ||
1285 | break; | ||
1286 | |||
1287 | case cmd_802_11_ad_hoc_join: | ||
1288 | ret = libertas_cmd_80211_ad_hoc_join(priv, cmdptr, pdata_buf); | ||
1289 | break; | ||
1290 | |||
1291 | case cmd_802_11_rssi: | ||
1292 | ret = wlan_cmd_802_11_rssi(priv, cmdptr); | ||
1293 | break; | ||
1294 | |||
1295 | case cmd_802_11_ad_hoc_stop: | ||
1296 | ret = libertas_cmd_80211_ad_hoc_stop(priv, cmdptr); | ||
1297 | break; | ||
1298 | |||
1299 | case cmd_802_11_enable_rsn: | ||
1300 | ret = wlan_cmd_802_11_enable_rsn(priv, cmdptr, cmd_action); | ||
1301 | break; | ||
1302 | |||
1303 | case cmd_802_11_key_material: | ||
1304 | ret = wlan_cmd_802_11_key_material(priv, cmdptr, | ||
1305 | cmd_action, cmd_oid, | ||
1306 | pdata_buf); | ||
1307 | break; | ||
1308 | |||
1309 | case cmd_802_11_pairwise_tsc: | ||
1310 | break; | ||
1311 | case cmd_802_11_group_tsc: | ||
1312 | break; | ||
1313 | |||
1314 | case cmd_802_11_mac_address: | ||
1315 | ret = wlan_cmd_802_11_mac_address(priv, cmdptr, cmd_action); | ||
1316 | break; | ||
1317 | |||
1318 | case cmd_802_11_eeprom_access: | ||
1319 | ret = wlan_cmd_802_11_eeprom_access(priv, cmdptr, | ||
1320 | cmd_action, pdata_buf); | ||
1321 | break; | ||
1322 | |||
1323 | case cmd_802_11_set_afc: | ||
1324 | case cmd_802_11_get_afc: | ||
1325 | |||
1326 | cmdptr->command = cpu_to_le16(cmd_no); | ||
1327 | cmdptr->size = | ||
1328 | cpu_to_le16(sizeof(struct cmd_ds_802_11_afc) + | ||
1329 | S_DS_GEN); | ||
1330 | |||
1331 | memmove(&cmdptr->params.afc, | ||
1332 | pdata_buf, sizeof(struct cmd_ds_802_11_afc)); | ||
1333 | |||
1334 | ret = 0; | ||
1335 | goto done; | ||
1336 | |||
1337 | case cmd_802_11d_domain_info: | ||
1338 | ret = libertas_cmd_802_11d_domain_info(priv, cmdptr, | ||
1339 | cmd_no, cmd_action); | ||
1340 | break; | ||
1341 | |||
1342 | case cmd_802_11_sleep_params: | ||
1343 | ret = wlan_cmd_802_11_sleep_params(priv, cmdptr, cmd_action); | ||
1344 | break; | ||
1345 | case cmd_802_11_inactivity_timeout: | ||
1346 | ret = wlan_cmd_802_11_inactivity_timeout(priv, cmdptr, | ||
1347 | cmd_action, pdata_buf); | ||
1348 | libertas_set_cmd_ctrl_node(priv, cmdnode, 0, 0, pdata_buf); | ||
1349 | break; | ||
1350 | |||
1351 | case cmd_802_11_tpc_cfg: | ||
1352 | cmdptr->command = cpu_to_le16(cmd_802_11_tpc_cfg); | ||
1353 | cmdptr->size = | ||
1354 | cpu_to_le16(sizeof(struct cmd_ds_802_11_tpc_cfg) + | ||
1355 | S_DS_GEN); | ||
1356 | |||
1357 | memmove(&cmdptr->params.tpccfg, | ||
1358 | pdata_buf, sizeof(struct cmd_ds_802_11_tpc_cfg)); | ||
1359 | |||
1360 | ret = 0; | ||
1361 | break; | ||
1362 | case cmd_802_11_led_gpio_ctrl: | ||
1363 | { | ||
1364 | struct mrvlietypes_ledgpio *gpio = | ||
1365 | (struct mrvlietypes_ledgpio*) | ||
1366 | cmdptr->params.ledgpio.data; | ||
1367 | |||
1368 | memmove(&cmdptr->params.ledgpio, | ||
1369 | pdata_buf, | ||
1370 | sizeof(struct cmd_ds_802_11_led_ctrl)); | ||
1371 | |||
1372 | cmdptr->command = | ||
1373 | cpu_to_le16(cmd_802_11_led_gpio_ctrl); | ||
1374 | |||
1375 | #define ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN 8 | ||
1376 | cmdptr->size = | ||
1377 | cpu_to_le16(gpio->header.len + S_DS_GEN + | ||
1378 | ACTION_NUMLED_TLVTYPE_LEN_FIELDS_LEN); | ||
1379 | gpio->header.len = cpu_to_le16(gpio->header.len); | ||
1380 | |||
1381 | ret = 0; | ||
1382 | break; | ||
1383 | } | ||
1384 | case cmd_802_11_pwr_cfg: | ||
1385 | cmdptr->command = cpu_to_le16(cmd_802_11_pwr_cfg); | ||
1386 | cmdptr->size = | ||
1387 | cpu_to_le16(sizeof(struct cmd_ds_802_11_pwr_cfg) + | ||
1388 | S_DS_GEN); | ||
1389 | memmove(&cmdptr->params.pwrcfg, pdata_buf, | ||
1390 | sizeof(struct cmd_ds_802_11_pwr_cfg)); | ||
1391 | |||
1392 | ret = 0; | ||
1393 | break; | ||
1394 | case cmd_bt_access: | ||
1395 | ret = wlan_cmd_bt_access(priv, cmdptr, cmd_action, pdata_buf); | ||
1396 | break; | ||
1397 | |||
1398 | case cmd_fwt_access: | ||
1399 | ret = wlan_cmd_fwt_access(priv, cmdptr, cmd_action, pdata_buf); | ||
1400 | break; | ||
1401 | |||
1402 | case cmd_mesh_access: | ||
1403 | ret = wlan_cmd_mesh_access(priv, cmdptr, cmd_action, pdata_buf); | ||
1404 | break; | ||
1405 | |||
1406 | case cmd_get_tsf: | ||
1407 | cmdptr->command = cpu_to_le16(cmd_get_tsf); | ||
1408 | cmdptr->size = | ||
1409 | cpu_to_le16(sizeof(struct cmd_ds_get_tsf) | ||
1410 | + S_DS_GEN); | ||
1411 | ret = 0; | ||
1412 | break; | ||
1413 | case cmd_802_11_tx_rate_query: | ||
1414 | cmdptr->command = | ||
1415 | cpu_to_le16(cmd_802_11_tx_rate_query); | ||
1416 | cmdptr->size = | ||
1417 | cpu_to_le16(sizeof(struct cmd_tx_rate_query) + | ||
1418 | S_DS_GEN); | ||
1419 | adapter->txrate = 0; | ||
1420 | ret = 0; | ||
1421 | break; | ||
1422 | default: | ||
1423 | lbs_pr_debug(1, "PREP_CMD: unknown command- %#x\n", cmd_no); | ||
1424 | ret = -1; | ||
1425 | break; | ||
1426 | } | ||
1427 | |||
1428 | /* return error, since the command preparation failed */ | ||
1429 | if (ret != 0) { | ||
1430 | lbs_pr_debug(1, "PREP_CMD: command preparation failed\n"); | ||
1431 | libertas_cleanup_and_insert_cmd(priv, cmdnode); | ||
1432 | ret = -1; | ||
1433 | goto done; | ||
1434 | } | ||
1435 | |||
1436 | cmdnode->cmdwaitqwoken = 0; | ||
1437 | |||
1438 | libertas_queue_cmd(adapter, cmdnode, 1); | ||
1439 | adapter->nr_cmd_pending++; | ||
1440 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1441 | |||
1442 | if (wait_option & cmd_option_waitforrsp) { | ||
1443 | lbs_pr_debug(1, "PREP_CMD: Wait for CMD response\n"); | ||
1444 | might_sleep(); | ||
1445 | wait_event_interruptible(cmdnode->cmdwait_q, | ||
1446 | cmdnode->cmdwaitqwoken); | ||
1447 | } | ||
1448 | |||
1449 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
1450 | if (adapter->cur_cmd_retcode) { | ||
1451 | lbs_pr_debug(1, "PREP_CMD: command failed with return code=%d\n", | ||
1452 | adapter->cur_cmd_retcode); | ||
1453 | adapter->cur_cmd_retcode = 0; | ||
1454 | ret = -1; | ||
1455 | } | ||
1456 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1457 | |||
1458 | done: | ||
1459 | LEAVE(); | ||
1460 | return ret; | ||
1461 | } | ||
1462 | |||
1463 | /** | ||
1464 | * @brief This function allocates the command buffer and link | ||
1465 | * it to command free queue. | ||
1466 | * | ||
1467 | * @param priv A pointer to wlan_private structure | ||
1468 | * @return 0 or -1 | ||
1469 | */ | ||
1470 | int libertas_allocate_cmd_buffer(wlan_private * priv) | ||
1471 | { | ||
1472 | int ret = 0; | ||
1473 | u32 ulbufsize; | ||
1474 | u32 i; | ||
1475 | struct cmd_ctrl_node *tempcmd_array; | ||
1476 | u8 *ptempvirtualaddr; | ||
1477 | wlan_adapter *adapter = priv->adapter; | ||
1478 | |||
1479 | ENTER(); | ||
1480 | |||
1481 | /* Allocate and initialize cmdCtrlNode */ | ||
1482 | ulbufsize = sizeof(struct cmd_ctrl_node) * MRVDRV_NUM_OF_CMD_BUFFER; | ||
1483 | |||
1484 | if (!(tempcmd_array = kmalloc(ulbufsize, GFP_KERNEL))) { | ||
1485 | lbs_pr_debug(1, | ||
1486 | "ALLOC_CMD_BUF: failed to allocate tempcmd_array\n"); | ||
1487 | ret = -1; | ||
1488 | goto done; | ||
1489 | } | ||
1490 | |||
1491 | adapter->cmd_array = tempcmd_array; | ||
1492 | memset(adapter->cmd_array, 0, ulbufsize); | ||
1493 | |||
1494 | /* Allocate and initialize command buffers */ | ||
1495 | ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; | ||
1496 | for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { | ||
1497 | if (!(ptempvirtualaddr = kmalloc(ulbufsize, GFP_KERNEL))) { | ||
1498 | lbs_pr_debug(1, | ||
1499 | "ALLOC_CMD_BUF: ptempvirtualaddr: out of memory\n"); | ||
1500 | ret = -1; | ||
1501 | goto done; | ||
1502 | } | ||
1503 | |||
1504 | memset(ptempvirtualaddr, 0, ulbufsize); | ||
1505 | |||
1506 | /* Update command buffer virtual */ | ||
1507 | tempcmd_array[i].bufvirtualaddr = ptempvirtualaddr; | ||
1508 | } | ||
1509 | |||
1510 | for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { | ||
1511 | init_waitqueue_head(&tempcmd_array[i].cmdwait_q); | ||
1512 | libertas_cleanup_and_insert_cmd(priv, &tempcmd_array[i]); | ||
1513 | } | ||
1514 | |||
1515 | ret = 0; | ||
1516 | done: | ||
1517 | LEAVE(); | ||
1518 | return ret; | ||
1519 | } | ||
1520 | |||
1521 | /** | ||
1522 | * @brief This function frees the command buffer. | ||
1523 | * | ||
1524 | * @param priv A pointer to wlan_private structure | ||
1525 | * @return 0 or -1 | ||
1526 | */ | ||
1527 | int libertas_free_cmd_buffer(wlan_private * priv) | ||
1528 | { | ||
1529 | u32 ulbufsize; | ||
1530 | unsigned int i; | ||
1531 | struct cmd_ctrl_node *tempcmd_array; | ||
1532 | wlan_adapter *adapter = priv->adapter; | ||
1533 | |||
1534 | ENTER(); | ||
1535 | |||
1536 | /* need to check if cmd array is allocated or not */ | ||
1537 | if (adapter->cmd_array == NULL) { | ||
1538 | lbs_pr_debug(1, "FREE_CMD_BUF: cmd_array is Null\n"); | ||
1539 | goto done; | ||
1540 | } | ||
1541 | |||
1542 | tempcmd_array = adapter->cmd_array; | ||
1543 | |||
1544 | /* Release shared memory buffers */ | ||
1545 | ulbufsize = MRVDRV_SIZE_OF_CMD_BUFFER; | ||
1546 | for (i = 0; i < MRVDRV_NUM_OF_CMD_BUFFER; i++) { | ||
1547 | if (tempcmd_array[i].bufvirtualaddr) { | ||
1548 | lbs_pr_debug(1, "Free all the array\n"); | ||
1549 | kfree(tempcmd_array[i].bufvirtualaddr); | ||
1550 | tempcmd_array[i].bufvirtualaddr = NULL; | ||
1551 | } | ||
1552 | } | ||
1553 | |||
1554 | /* Release cmd_ctrl_node */ | ||
1555 | if (adapter->cmd_array) { | ||
1556 | lbs_pr_debug(1, "Free cmd_array\n"); | ||
1557 | kfree(adapter->cmd_array); | ||
1558 | adapter->cmd_array = NULL; | ||
1559 | } | ||
1560 | |||
1561 | done: | ||
1562 | LEAVE(); | ||
1563 | return 0; | ||
1564 | } | ||
1565 | |||
1566 | /** | ||
1567 | * @brief This function gets a free command node if available in | ||
1568 | * command free queue. | ||
1569 | * | ||
1570 | * @param priv A pointer to wlan_private structure | ||
1571 | * @return cmd_ctrl_node A pointer to cmd_ctrl_node structure or NULL | ||
1572 | */ | ||
1573 | struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv) | ||
1574 | { | ||
1575 | struct cmd_ctrl_node *tempnode; | ||
1576 | wlan_adapter *adapter = priv->adapter; | ||
1577 | unsigned long flags; | ||
1578 | |||
1579 | if (!adapter) | ||
1580 | return NULL; | ||
1581 | |||
1582 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
1583 | |||
1584 | if (!list_empty(&adapter->cmdfreeq)) { | ||
1585 | tempnode = (struct cmd_ctrl_node *)adapter->cmdfreeq.next; | ||
1586 | list_del((struct list_head *)tempnode); | ||
1587 | } else { | ||
1588 | lbs_pr_debug(1, "GET_CMD_NODE: cmd_ctrl_node is not available\n"); | ||
1589 | tempnode = NULL; | ||
1590 | } | ||
1591 | |||
1592 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1593 | |||
1594 | if (tempnode) { | ||
1595 | lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode available\n"); | ||
1596 | lbs_pr_debug(3, "GET_CMD_NODE: cmdCtrlNode Address = %p\n", | ||
1597 | tempnode); | ||
1598 | cleanup_cmdnode(tempnode); | ||
1599 | } | ||
1600 | |||
1601 | return tempnode; | ||
1602 | } | ||
1603 | |||
1604 | /** | ||
1605 | * @brief This function cleans command node. | ||
1606 | * | ||
1607 | * @param ptempnode A pointer to cmdCtrlNode structure | ||
1608 | * @return n/a | ||
1609 | */ | ||
1610 | static void cleanup_cmdnode(struct cmd_ctrl_node *ptempnode) | ||
1611 | { | ||
1612 | if (!ptempnode) | ||
1613 | return; | ||
1614 | ptempnode->cmdwaitqwoken = 1; | ||
1615 | wake_up_interruptible(&ptempnode->cmdwait_q); | ||
1616 | ptempnode->status = 0; | ||
1617 | ptempnode->cmd_oid = (u32) 0; | ||
1618 | ptempnode->wait_option = 0; | ||
1619 | ptempnode->pdata_buf = NULL; | ||
1620 | |||
1621 | if (ptempnode->bufvirtualaddr != NULL) | ||
1622 | memset(ptempnode->bufvirtualaddr, 0, MRVDRV_SIZE_OF_CMD_BUFFER); | ||
1623 | return; | ||
1624 | } | ||
1625 | |||
1626 | /** | ||
1627 | * @brief This function initializes the command node. | ||
1628 | * | ||
1629 | * @param priv A pointer to wlan_private structure | ||
1630 | * @param ptempnode A pointer to cmd_ctrl_node structure | ||
1631 | * @param cmd_oid cmd oid: treated as sub command | ||
1632 | * @param wait_option wait option: wait response or not | ||
1633 | * @param pdata_buf A pointer to informaion buffer | ||
1634 | * @return 0 or -1 | ||
1635 | */ | ||
1636 | void libertas_set_cmd_ctrl_node(wlan_private * priv, | ||
1637 | struct cmd_ctrl_node *ptempnode, | ||
1638 | u32 cmd_oid, u16 wait_option, void *pdata_buf) | ||
1639 | { | ||
1640 | ENTER(); | ||
1641 | |||
1642 | if (!ptempnode) | ||
1643 | return; | ||
1644 | |||
1645 | ptempnode->cmd_oid = cmd_oid; | ||
1646 | ptempnode->wait_option = wait_option; | ||
1647 | ptempnode->pdata_buf = pdata_buf; | ||
1648 | |||
1649 | LEAVE(); | ||
1650 | } | ||
1651 | |||
1652 | /** | ||
1653 | * @brief This function executes next command in command | ||
1654 | * pending queue. It will put fimware back to PS mode | ||
1655 | * if applicable. | ||
1656 | * | ||
1657 | * @param priv A pointer to wlan_private structure | ||
1658 | * @return 0 or -1 | ||
1659 | */ | ||
1660 | int libertas_execute_next_command(wlan_private * priv) | ||
1661 | { | ||
1662 | wlan_adapter *adapter = priv->adapter; | ||
1663 | struct cmd_ctrl_node *cmdnode = NULL; | ||
1664 | struct cmd_ds_command *cmdptr; | ||
1665 | unsigned long flags; | ||
1666 | int ret = 0; | ||
1667 | |||
1668 | lbs_pr_debug(1, "libertas_execute_next_command\n"); | ||
1669 | |||
1670 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
1671 | |||
1672 | if (adapter->cur_cmd) { | ||
1673 | lbs_pr_alert( "EXEC_NEXT_CMD: there is command in processing!\n"); | ||
1674 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1675 | ret = -1; | ||
1676 | goto done; | ||
1677 | } | ||
1678 | |||
1679 | if (!list_empty(&adapter->cmdpendingq)) { | ||
1680 | cmdnode = (struct cmd_ctrl_node *) | ||
1681 | adapter->cmdpendingq.next; | ||
1682 | } | ||
1683 | |||
1684 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1685 | |||
1686 | if (cmdnode) { | ||
1687 | lbs_pr_debug(1, | ||
1688 | "EXEC_NEXT_CMD: Got next command from cmdpendingq\n"); | ||
1689 | cmdptr = (struct cmd_ds_command *)cmdnode->bufvirtualaddr; | ||
1690 | |||
1691 | if (is_command_allowed_in_ps(cmdptr->command)) { | ||
1692 | if ((adapter->psstate == PS_STATE_SLEEP) | ||
1693 | || (adapter->psstate == PS_STATE_PRE_SLEEP) | ||
1694 | ) { | ||
1695 | lbs_pr_debug(1, | ||
1696 | "EXEC_NEXT_CMD: Cannot send cmd 0x%x in psstate %d\n", | ||
1697 | cmdptr->command, adapter->psstate); | ||
1698 | ret = -1; | ||
1699 | goto done; | ||
1700 | } | ||
1701 | lbs_pr_debug(1, "EXEC_NEXT_CMD: OK to send command " | ||
1702 | "0x%x in psstate %d\n", | ||
1703 | cmdptr->command, adapter->psstate); | ||
1704 | } else if (adapter->psstate != PS_STATE_FULL_POWER) { | ||
1705 | /* | ||
1706 | * 1. Non-PS command: | ||
1707 | * Queue it. set needtowakeup to TRUE if current state | ||
1708 | * is SLEEP, otherwise call libertas_ps_wakeup to send Exit_PS. | ||
1709 | * 2. PS command but not Exit_PS: | ||
1710 | * Ignore it. | ||
1711 | * 3. PS command Exit_PS: | ||
1712 | * Set needtowakeup to TRUE if current state is SLEEP, | ||
1713 | * otherwise send this command down to firmware | ||
1714 | * immediately. | ||
1715 | */ | ||
1716 | if (cmdptr->command != | ||
1717 | cpu_to_le16(cmd_802_11_ps_mode)) { | ||
1718 | /* Prepare to send Exit PS, | ||
1719 | * this non PS command will be sent later */ | ||
1720 | if ((adapter->psstate == PS_STATE_SLEEP) | ||
1721 | || (adapter->psstate == PS_STATE_PRE_SLEEP) | ||
1722 | ) { | ||
1723 | /* w/ new scheme, it will not reach here. | ||
1724 | since it is blocked in main_thread. */ | ||
1725 | adapter->needtowakeup = 1; | ||
1726 | } else | ||
1727 | libertas_ps_wakeup(priv, 0); | ||
1728 | |||
1729 | ret = 0; | ||
1730 | goto done; | ||
1731 | } else { | ||
1732 | /* | ||
1733 | * PS command. Ignore it if it is not Exit_PS. | ||
1734 | * otherwise send it down immediately. | ||
1735 | */ | ||
1736 | struct cmd_ds_802_11_ps_mode *psm = | ||
1737 | &cmdptr->params.psmode; | ||
1738 | |||
1739 | lbs_pr_debug(1, | ||
1740 | "EXEC_NEXT_CMD: PS cmd- action=0x%x\n", | ||
1741 | psm->action); | ||
1742 | if (psm->action != | ||
1743 | cpu_to_le16(cmd_subcmd_exit_ps)) { | ||
1744 | lbs_pr_debug(1, | ||
1745 | "EXEC_NEXT_CMD: Ignore Enter PS cmd\n"); | ||
1746 | list_del((struct list_head *)cmdnode); | ||
1747 | libertas_cleanup_and_insert_cmd(priv, cmdnode); | ||
1748 | |||
1749 | ret = 0; | ||
1750 | goto done; | ||
1751 | } | ||
1752 | |||
1753 | if ((adapter->psstate == PS_STATE_SLEEP) | ||
1754 | || (adapter->psstate == PS_STATE_PRE_SLEEP) | ||
1755 | ) { | ||
1756 | lbs_pr_debug(1, | ||
1757 | "EXEC_NEXT_CMD: Ignore ExitPS cmd in sleep\n"); | ||
1758 | list_del((struct list_head *)cmdnode); | ||
1759 | libertas_cleanup_and_insert_cmd(priv, cmdnode); | ||
1760 | adapter->needtowakeup = 1; | ||
1761 | |||
1762 | ret = 0; | ||
1763 | goto done; | ||
1764 | } | ||
1765 | |||
1766 | lbs_pr_debug(1, | ||
1767 | "EXEC_NEXT_CMD: Sending Exit_PS down...\n"); | ||
1768 | } | ||
1769 | } | ||
1770 | list_del((struct list_head *)cmdnode); | ||
1771 | lbs_pr_debug(1, "EXEC_NEXT_CMD: Sending 0x%04X command\n", | ||
1772 | cmdptr->command); | ||
1773 | DownloadcommandToStation(priv, cmdnode); | ||
1774 | } else { | ||
1775 | /* | ||
1776 | * check if in power save mode, if yes, put the device back | ||
1777 | * to PS mode | ||
1778 | */ | ||
1779 | if ((adapter->psmode != wlan802_11powermodecam) && | ||
1780 | (adapter->psstate == PS_STATE_FULL_POWER) && | ||
1781 | (adapter->connect_status == libertas_connected)) { | ||
1782 | if (adapter->secinfo.WPAenabled | ||
1783 | || adapter->secinfo.WPA2enabled) { | ||
1784 | /* check for valid WPA group keys */ | ||
1785 | if (adapter->wpa_mcast_key.len | ||
1786 | || adapter->wpa_unicast_key.len) { | ||
1787 | lbs_pr_debug(1, | ||
1788 | "EXEC_NEXT_CMD: WPA enabled and GTK_SET" | ||
1789 | " go back to PS_SLEEP"); | ||
1790 | libertas_ps_sleep(priv, 0); | ||
1791 | } | ||
1792 | } else { | ||
1793 | lbs_pr_debug(1, | ||
1794 | "EXEC_NEXT_CMD: command PendQ is empty," | ||
1795 | " go back to PS_SLEEP"); | ||
1796 | libertas_ps_sleep(priv, 0); | ||
1797 | } | ||
1798 | } | ||
1799 | } | ||
1800 | |||
1801 | ret = 0; | ||
1802 | done: | ||
1803 | return ret; | ||
1804 | } | ||
1805 | |||
1806 | void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str) | ||
1807 | { | ||
1808 | union iwreq_data iwrq; | ||
1809 | u8 buf[50]; | ||
1810 | |||
1811 | ENTER(); | ||
1812 | |||
1813 | memset(&iwrq, 0, sizeof(union iwreq_data)); | ||
1814 | memset(buf, 0, sizeof(buf)); | ||
1815 | |||
1816 | snprintf(buf, sizeof(buf) - 1, "%s", str); | ||
1817 | |||
1818 | iwrq.data.length = strlen(buf) + 1 + IW_EV_LCP_LEN; | ||
1819 | |||
1820 | /* Send Event to upper layer */ | ||
1821 | lbs_pr_debug(1, "Event Indication string = %s\n", | ||
1822 | (char *)buf); | ||
1823 | lbs_pr_debug(1, "Event Indication String length = %d\n", iwrq.data.length); | ||
1824 | |||
1825 | lbs_pr_debug(1, "Sending wireless event IWEVCUSTOM for %s\n", str); | ||
1826 | wireless_send_event(priv->wlan_dev.netdev, IWEVCUSTOM, &iwrq, buf); | ||
1827 | |||
1828 | LEAVE(); | ||
1829 | return; | ||
1830 | } | ||
1831 | |||
1832 | static int sendconfirmsleep(wlan_private * priv, u8 * cmdptr, u16 size) | ||
1833 | { | ||
1834 | unsigned long flags; | ||
1835 | wlan_adapter *adapter = priv->adapter; | ||
1836 | int ret = 0; | ||
1837 | |||
1838 | ENTER(); | ||
1839 | |||
1840 | lbs_pr_debug(1, "SEND_SLEEPC_CMD: Before download, size of cmd = %d\n", | ||
1841 | size); | ||
1842 | |||
1843 | lbs_dbg_hex("SEND_SLEEPC_CMD: Sleep confirm command", cmdptr, size); | ||
1844 | |||
1845 | ret = libertas_sbi_host_to_card(priv, MVMS_CMD, cmdptr, size); | ||
1846 | priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; | ||
1847 | |||
1848 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
1849 | if (adapter->intcounter || adapter->currenttxskb) | ||
1850 | lbs_pr_debug(1, "SEND_SLEEPC_CMD: intcounter=%d currenttxskb=%p\n", | ||
1851 | adapter->intcounter, adapter->currenttxskb); | ||
1852 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1853 | |||
1854 | if (ret) { | ||
1855 | lbs_pr_alert( | ||
1856 | "SEND_SLEEPC_CMD: Host to Card failed for Confirm Sleep\n"); | ||
1857 | } else { | ||
1858 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
1859 | if (!adapter->intcounter) { | ||
1860 | adapter->psstate = PS_STATE_SLEEP; | ||
1861 | } else { | ||
1862 | lbs_pr_debug(1, "SEND_SLEEPC_CMD: After sent,IntC=%d\n", | ||
1863 | adapter->intcounter); | ||
1864 | } | ||
1865 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1866 | |||
1867 | lbs_pr_debug(1, "SEND_SLEEPC_CMD: Sent Confirm Sleep command\n"); | ||
1868 | lbs_pr_debug(1, "+"); | ||
1869 | } | ||
1870 | |||
1871 | LEAVE(); | ||
1872 | return ret; | ||
1873 | } | ||
1874 | |||
1875 | void libertas_ps_sleep(wlan_private * priv, int wait_option) | ||
1876 | { | ||
1877 | |||
1878 | ENTER(); | ||
1879 | |||
1880 | /* | ||
1881 | * PS is currently supported only in Infrastructure mode | ||
1882 | * Remove this check if it is to be supported in IBSS mode also | ||
1883 | */ | ||
1884 | |||
1885 | libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, | ||
1886 | cmd_subcmd_enter_ps, wait_option, 0, NULL); | ||
1887 | |||
1888 | LEAVE(); | ||
1889 | return; | ||
1890 | } | ||
1891 | |||
1892 | /** | ||
1893 | * @brief This function sends Eixt_PS command to firmware. | ||
1894 | * | ||
1895 | * @param priv A pointer to wlan_private structure | ||
1896 | * @param wait_option wait response or not | ||
1897 | * @return n/a | ||
1898 | */ | ||
1899 | void libertas_ps_wakeup(wlan_private * priv, int wait_option) | ||
1900 | { | ||
1901 | enum WLAN_802_11_POWER_MODE Localpsmode; | ||
1902 | |||
1903 | ENTER(); | ||
1904 | |||
1905 | Localpsmode = wlan802_11powermodecam; | ||
1906 | |||
1907 | lbs_pr_debug(1, "Exit_PS: Localpsmode = %d\n", Localpsmode); | ||
1908 | |||
1909 | libertas_prepare_and_send_command(priv, cmd_802_11_ps_mode, | ||
1910 | cmd_subcmd_exit_ps, | ||
1911 | wait_option, 0, &Localpsmode); | ||
1912 | |||
1913 | LEAVE(); | ||
1914 | return; | ||
1915 | } | ||
1916 | |||
1917 | /** | ||
1918 | * @brief This function checks condition and prepares to | ||
1919 | * send sleep confirm command to firmware if ok. | ||
1920 | * | ||
1921 | * @param priv A pointer to wlan_private structure | ||
1922 | * @param psmode Power Saving mode | ||
1923 | * @return n/a | ||
1924 | */ | ||
1925 | void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode) | ||
1926 | { | ||
1927 | unsigned long flags =0; | ||
1928 | wlan_adapter *adapter = priv->adapter; | ||
1929 | u8 allowed = 1; | ||
1930 | |||
1931 | ENTER(); | ||
1932 | |||
1933 | if (priv->wlan_dev.dnld_sent) { | ||
1934 | allowed = 0; | ||
1935 | lbs_pr_debug(1, "D"); | ||
1936 | } | ||
1937 | |||
1938 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
1939 | if (adapter->cur_cmd) { | ||
1940 | allowed = 0; | ||
1941 | lbs_pr_debug(1, "C"); | ||
1942 | } | ||
1943 | if (adapter->intcounter > 0) { | ||
1944 | allowed = 0; | ||
1945 | lbs_pr_debug(1, "I%d", adapter->intcounter); | ||
1946 | } | ||
1947 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
1948 | |||
1949 | if (allowed) { | ||
1950 | lbs_pr_debug(1, "Sending libertas_ps_confirm_sleep\n"); | ||
1951 | sendconfirmsleep(priv, (u8 *) & adapter->libertas_ps_confirm_sleep, | ||
1952 | sizeof(struct PS_CMD_ConfirmSleep)); | ||
1953 | } else { | ||
1954 | lbs_pr_debug(1, "Sleep Confirm has been delayed\n"); | ||
1955 | } | ||
1956 | |||
1957 | LEAVE(); | ||
1958 | } | ||
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c new file mode 100644 index 000000000000..cdb012c7e9cf --- /dev/null +++ b/drivers/net/wireless/libertas/cmdresp.c | |||
@@ -0,0 +1,1031 @@ | |||
1 | /** | ||
2 | * This file contains the handling of command | ||
3 | * responses as well as events generated by firmware. | ||
4 | */ | ||
5 | #include <linux/delay.h> | ||
6 | #include <linux/if_arp.h> | ||
7 | #include <linux/netdevice.h> | ||
8 | |||
9 | #include <net/iw_handler.h> | ||
10 | |||
11 | #include "host.h" | ||
12 | #include "sbi.h" | ||
13 | #include "decl.h" | ||
14 | #include "defs.h" | ||
15 | #include "dev.h" | ||
16 | #include "join.h" | ||
17 | #include "wext.h" | ||
18 | |||
19 | /** | ||
20 | * @brief This function handles disconnect event. it | ||
21 | * reports disconnect to upper layer, clean tx/rx packets, | ||
22 | * reset link state etc. | ||
23 | * | ||
24 | * @param priv A pointer to wlan_private structure | ||
25 | * @return n/a | ||
26 | */ | ||
27 | void libertas_mac_event_disconnected(wlan_private * priv) | ||
28 | { | ||
29 | wlan_adapter *adapter = priv->adapter; | ||
30 | union iwreq_data wrqu; | ||
31 | |||
32 | if (adapter->connect_status != libertas_connected) | ||
33 | return; | ||
34 | |||
35 | lbs_pr_debug(1, "Handles disconnect event.\n"); | ||
36 | |||
37 | memset(wrqu.ap_addr.sa_data, 0x00, ETH_ALEN); | ||
38 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
39 | |||
40 | /* | ||
41 | * Cisco AP sends EAP failure and de-auth in less than 0.5 ms. | ||
42 | * It causes problem in the Supplicant | ||
43 | */ | ||
44 | |||
45 | msleep_interruptible(1000); | ||
46 | wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); | ||
47 | |||
48 | /* Free Tx and Rx packets */ | ||
49 | kfree_skb(priv->adapter->currenttxskb); | ||
50 | priv->adapter->currenttxskb = NULL; | ||
51 | |||
52 | /* report disconnect to upper layer */ | ||
53 | netif_stop_queue(priv->wlan_dev.netdev); | ||
54 | netif_carrier_off(priv->wlan_dev.netdev); | ||
55 | |||
56 | /* reset SNR/NF/RSSI values */ | ||
57 | memset(adapter->SNR, 0x00, sizeof(adapter->SNR)); | ||
58 | memset(adapter->NF, 0x00, sizeof(adapter->NF)); | ||
59 | memset(adapter->RSSI, 0x00, sizeof(adapter->RSSI)); | ||
60 | memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); | ||
61 | memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); | ||
62 | adapter->nextSNRNF = 0; | ||
63 | adapter->numSNRNF = 0; | ||
64 | adapter->rxpd_rate = 0; | ||
65 | lbs_pr_debug(1, "Current SSID=%s, ssid length=%u\n", | ||
66 | adapter->curbssparams.ssid.ssid, | ||
67 | adapter->curbssparams.ssid.ssidlength); | ||
68 | lbs_pr_debug(1, "Previous SSID=%s, ssid length=%u\n", | ||
69 | adapter->previousssid.ssid, adapter->previousssid.ssidlength); | ||
70 | |||
71 | /* reset internal flags */ | ||
72 | adapter->secinfo.WPAenabled = 0; | ||
73 | adapter->secinfo.WPA2enabled = 0; | ||
74 | adapter->wpa_ie_len = 0; | ||
75 | adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE; | ||
76 | adapter->secinfo.Encryptionmode = CIPHER_NONE; | ||
77 | |||
78 | adapter->connect_status = libertas_disconnected; | ||
79 | |||
80 | /* | ||
81 | * memorize the previous SSID and BSSID | ||
82 | * it could be used for re-assoc | ||
83 | */ | ||
84 | memcpy(&adapter->previousssid, | ||
85 | &adapter->curbssparams.ssid, sizeof(struct WLAN_802_11_SSID)); | ||
86 | memcpy(adapter->previousbssid, | ||
87 | adapter->curbssparams.bssid, ETH_ALEN); | ||
88 | |||
89 | /* need to erase the current SSID and BSSID info */ | ||
90 | adapter->pattemptedbssdesc = NULL; | ||
91 | memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); | ||
92 | |||
93 | if (adapter->psstate != PS_STATE_FULL_POWER) { | ||
94 | /* make firmware to exit PS mode */ | ||
95 | lbs_pr_debug(1, "Disconnected, so exit PS mode.\n"); | ||
96 | libertas_ps_wakeup(priv, 0); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | /** | ||
101 | * @brief This function handles MIC failure event. | ||
102 | * | ||
103 | * @param priv A pointer to wlan_private structure | ||
104 | * @para event the event id | ||
105 | * @return n/a | ||
106 | */ | ||
107 | static void handle_mic_failureevent(wlan_private * priv, u32 event) | ||
108 | { | ||
109 | char buf[50]; | ||
110 | |||
111 | memset(buf, 0, sizeof(buf)); | ||
112 | |||
113 | sprintf(buf, "%s", "MLME-MICHAELMICFAILURE.indication "); | ||
114 | |||
115 | if (event == MACREG_INT_CODE_MIC_ERR_UNICAST) { | ||
116 | strcat(buf, "unicast "); | ||
117 | } else { | ||
118 | strcat(buf, "multicast "); | ||
119 | } | ||
120 | |||
121 | libertas_send_iwevcustom_event(priv, buf); | ||
122 | } | ||
123 | |||
124 | static int wlan_ret_reg_access(wlan_private * priv, | ||
125 | u16 type, struct cmd_ds_command *resp) | ||
126 | { | ||
127 | wlan_adapter *adapter = priv->adapter; | ||
128 | |||
129 | ENTER(); | ||
130 | |||
131 | switch (type) { | ||
132 | case cmd_ret_mac_reg_access: | ||
133 | { | ||
134 | struct cmd_ds_mac_reg_access *reg; | ||
135 | |||
136 | reg = | ||
137 | (struct cmd_ds_mac_reg_access *)&resp->params. | ||
138 | macreg; | ||
139 | |||
140 | adapter->offsetvalue.offset = reg->offset; | ||
141 | adapter->offsetvalue.value = reg->value; | ||
142 | break; | ||
143 | } | ||
144 | |||
145 | case cmd_ret_bbp_reg_access: | ||
146 | { | ||
147 | struct cmd_ds_bbp_reg_access *reg; | ||
148 | reg = | ||
149 | (struct cmd_ds_bbp_reg_access *)&resp->params. | ||
150 | bbpreg; | ||
151 | |||
152 | adapter->offsetvalue.offset = reg->offset; | ||
153 | adapter->offsetvalue.value = reg->value; | ||
154 | break; | ||
155 | } | ||
156 | |||
157 | case cmd_ret_rf_reg_access: | ||
158 | { | ||
159 | struct cmd_ds_rf_reg_access *reg; | ||
160 | reg = | ||
161 | (struct cmd_ds_rf_reg_access *)&resp->params. | ||
162 | rfreg; | ||
163 | |||
164 | adapter->offsetvalue.offset = reg->offset; | ||
165 | adapter->offsetvalue.value = reg->value; | ||
166 | break; | ||
167 | } | ||
168 | |||
169 | default: | ||
170 | LEAVE(); | ||
171 | return -1; | ||
172 | } | ||
173 | |||
174 | LEAVE(); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int wlan_ret_get_hw_spec(wlan_private * priv, | ||
179 | struct cmd_ds_command *resp) | ||
180 | { | ||
181 | u32 i; | ||
182 | struct cmd_ds_get_hw_spec *hwspec = &resp->params.hwspec; | ||
183 | wlan_adapter *adapter = priv->adapter; | ||
184 | int ret = 0; | ||
185 | |||
186 | ENTER(); | ||
187 | |||
188 | adapter->fwcapinfo = le32_to_cpu(hwspec->fwcapinfo); | ||
189 | |||
190 | adapter->fwreleasenumber = hwspec->fwreleasenumber; | ||
191 | |||
192 | lbs_pr_debug(1, "GET_HW_SPEC: FWReleaseVersion- 0x%X\n", | ||
193 | adapter->fwreleasenumber); | ||
194 | lbs_pr_debug(1, "GET_HW_SPEC: Permanent addr- %2x:%2x:%2x:%2x:%2x:%2x\n", | ||
195 | hwspec->permanentaddr[0], hwspec->permanentaddr[1], | ||
196 | hwspec->permanentaddr[2], hwspec->permanentaddr[3], | ||
197 | hwspec->permanentaddr[4], hwspec->permanentaddr[5]); | ||
198 | lbs_pr_debug(1, "GET_HW_SPEC: hwifversion=0x%X version=0x%X\n", | ||
199 | hwspec->hwifversion, hwspec->version); | ||
200 | |||
201 | adapter->regioncode = le16_to_cpu(hwspec->regioncode); | ||
202 | |||
203 | for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { | ||
204 | /* use the region code to search for the index */ | ||
205 | if (adapter->regioncode == libertas_region_code_to_index[i]) { | ||
206 | adapter->regiontableindex = (u16) i; | ||
207 | break; | ||
208 | } | ||
209 | } | ||
210 | |||
211 | /* if it's unidentified region code, use the default (USA) */ | ||
212 | if (i >= MRVDRV_MAX_REGION_CODE) { | ||
213 | adapter->regioncode = 0x10; | ||
214 | adapter->regiontableindex = 0; | ||
215 | lbs_pr_info( | ||
216 | "unidentified region code, use the default (USA)\n"); | ||
217 | } | ||
218 | |||
219 | if (adapter->current_addr[0] == 0xff) { | ||
220 | memmove(adapter->current_addr, hwspec->permanentaddr, | ||
221 | ETH_ALEN); | ||
222 | } | ||
223 | |||
224 | memcpy(priv->wlan_dev.netdev->dev_addr, adapter->current_addr, ETH_ALEN); | ||
225 | memcpy(priv->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); | ||
226 | |||
227 | if (libertas_set_regiontable(priv, adapter->regioncode, 0)) { | ||
228 | ret = -1; | ||
229 | goto done; | ||
230 | } | ||
231 | |||
232 | if (libertas_set_universaltable(priv, 0)) { | ||
233 | ret = -1; | ||
234 | goto done; | ||
235 | } | ||
236 | |||
237 | done: | ||
238 | LEAVE(); | ||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | static int wlan_ret_802_11_sleep_params(wlan_private * priv, | ||
243 | struct cmd_ds_command *resp) | ||
244 | { | ||
245 | struct cmd_ds_802_11_sleep_params *sp = &resp->params.sleep_params; | ||
246 | wlan_adapter *adapter = priv->adapter; | ||
247 | |||
248 | ENTER(); | ||
249 | |||
250 | lbs_pr_debug(1, "error=%x offset=%x stabletime=%x calcontrol=%x\n" | ||
251 | " extsleepclk=%x\n", sp->error, sp->offset, | ||
252 | sp->stabletime, sp->calcontrol, sp->externalsleepclk); | ||
253 | adapter->sp.sp_error = le16_to_cpu(sp->error); | ||
254 | adapter->sp.sp_offset = le16_to_cpu(sp->offset); | ||
255 | adapter->sp.sp_stabletime = le16_to_cpu(sp->stabletime); | ||
256 | adapter->sp.sp_calcontrol = le16_to_cpu(sp->calcontrol); | ||
257 | adapter->sp.sp_extsleepclk = le16_to_cpu(sp->externalsleepclk); | ||
258 | adapter->sp.sp_reserved = le16_to_cpu(sp->reserved); | ||
259 | |||
260 | LEAVE(); | ||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | static int wlan_ret_802_11_stat(wlan_private * priv, | ||
265 | struct cmd_ds_command *resp) | ||
266 | { | ||
267 | /* currently adapter->wlan802_11Stat is unused | ||
268 | |||
269 | struct cmd_ds_802_11_get_stat *p11Stat = &resp->params.gstat; | ||
270 | wlan_adapter *adapter = priv->adapter; | ||
271 | |||
272 | // TODO Convert it to Big endian befor copy | ||
273 | memcpy(&adapter->wlan802_11Stat, | ||
274 | p11Stat, sizeof(struct cmd_ds_802_11_get_stat)); | ||
275 | */ | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | static int wlan_ret_802_11_snmp_mib(wlan_private * priv, | ||
280 | struct cmd_ds_command *resp) | ||
281 | { | ||
282 | struct cmd_ds_802_11_snmp_mib *smib = &resp->params.smib; | ||
283 | u16 oid = le16_to_cpu(smib->oid); | ||
284 | u16 querytype = le16_to_cpu(smib->querytype); | ||
285 | |||
286 | ENTER(); | ||
287 | |||
288 | lbs_pr_debug(1, "SNMP_RESP: value of the oid = %x, querytype=%x\n", oid, | ||
289 | querytype); | ||
290 | lbs_pr_debug(1, "SNMP_RESP: Buf size = %x\n", | ||
291 | le16_to_cpu(smib->bufsize)); | ||
292 | |||
293 | if (querytype == cmd_act_get) { | ||
294 | switch (oid) { | ||
295 | case fragthresh_i: | ||
296 | priv->adapter->fragthsd = | ||
297 | le16_to_cpu(* | ||
298 | ((unsigned short *)(smib->value))); | ||
299 | lbs_pr_debug(1, "SNMP_RESP: fragthsd =%u\n", | ||
300 | priv->adapter->fragthsd); | ||
301 | break; | ||
302 | case rtsthresh_i: | ||
303 | priv->adapter->rtsthsd = | ||
304 | le16_to_cpu(* | ||
305 | ((unsigned short *)(smib->value))); | ||
306 | lbs_pr_debug(1, "SNMP_RESP: rtsthsd =%u\n", | ||
307 | priv->adapter->rtsthsd); | ||
308 | break; | ||
309 | case short_retrylim_i: | ||
310 | priv->adapter->txretrycount = | ||
311 | le16_to_cpu(* | ||
312 | ((unsigned short *)(smib->value))); | ||
313 | lbs_pr_debug(1, "SNMP_RESP: txretrycount =%u\n", | ||
314 | priv->adapter->rtsthsd); | ||
315 | break; | ||
316 | default: | ||
317 | break; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | LEAVE(); | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int wlan_ret_802_11_key_material(wlan_private * priv, | ||
326 | struct cmd_ds_command *resp) | ||
327 | { | ||
328 | struct cmd_ds_802_11_key_material *pkeymaterial = | ||
329 | &resp->params.keymaterial; | ||
330 | wlan_adapter *adapter = priv->adapter; | ||
331 | u16 action = le16_to_cpu(pkeymaterial->action); | ||
332 | |||
333 | ENTER(); | ||
334 | |||
335 | /* Copy the returned key to driver private data */ | ||
336 | if (action == cmd_act_get) { | ||
337 | u8 * buf_ptr = (u8 *) &pkeymaterial->keyParamSet; | ||
338 | u8 * resp_end = (u8 *) (resp + le16_to_cpu(resp->size)); | ||
339 | |||
340 | while (buf_ptr < resp_end) { | ||
341 | struct MrvlIEtype_keyParamSet * pkeyparamset = | ||
342 | (struct MrvlIEtype_keyParamSet *) buf_ptr; | ||
343 | struct WLAN_802_11_KEY * pkey; | ||
344 | u16 key_info = le16_to_cpu(pkeyparamset->keyinfo); | ||
345 | u16 param_set_len = le16_to_cpu(pkeyparamset->length); | ||
346 | u8 * end; | ||
347 | u16 key_len = le16_to_cpu(pkeyparamset->keylen); | ||
348 | |||
349 | end = (u8 *) pkeyparamset + sizeof (pkeyparamset->type) | ||
350 | + sizeof (pkeyparamset->length) | ||
351 | + param_set_len; | ||
352 | /* Make sure we don't access past the end of the IEs */ | ||
353 | if (end > resp_end) | ||
354 | break; | ||
355 | |||
356 | if (key_info & KEY_INFO_WPA_UNICAST) | ||
357 | pkey = &adapter->wpa_unicast_key; | ||
358 | else if (key_info & KEY_INFO_WPA_MCAST) | ||
359 | pkey = &adapter->wpa_mcast_key; | ||
360 | else | ||
361 | break; | ||
362 | |||
363 | /* Copy returned key into driver */ | ||
364 | memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); | ||
365 | if (key_len > sizeof(pkey->key)) | ||
366 | break; | ||
367 | pkey->type = le16_to_cpu(pkeyparamset->keytypeid); | ||
368 | pkey->flags = le16_to_cpu(pkeyparamset->keyinfo); | ||
369 | pkey->len = le16_to_cpu(pkeyparamset->keylen); | ||
370 | memcpy(pkey->key, pkeyparamset->key, pkey->len); | ||
371 | |||
372 | buf_ptr = end + 1; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | LEAVE(); | ||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | static int wlan_ret_802_11_mac_address(wlan_private * priv, | ||
381 | struct cmd_ds_command *resp) | ||
382 | { | ||
383 | struct cmd_ds_802_11_mac_address *macadd = &resp->params.macadd; | ||
384 | wlan_adapter *adapter = priv->adapter; | ||
385 | |||
386 | ENTER(); | ||
387 | |||
388 | memcpy(adapter->current_addr, macadd->macadd, ETH_ALEN); | ||
389 | |||
390 | LEAVE(); | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int wlan_ret_802_11_rf_tx_power(wlan_private * priv, | ||
395 | struct cmd_ds_command *resp) | ||
396 | { | ||
397 | struct cmd_ds_802_11_rf_tx_power *rtp = &resp->params.txp; | ||
398 | wlan_adapter *adapter = priv->adapter; | ||
399 | |||
400 | ENTER(); | ||
401 | |||
402 | adapter->txpowerlevel = le16_to_cpu(rtp->currentlevel); | ||
403 | |||
404 | lbs_pr_debug(1, "Current TxPower Level = %d\n", adapter->txpowerlevel); | ||
405 | |||
406 | LEAVE(); | ||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static int wlan_ret_802_11_rf_antenna(wlan_private * priv, | ||
411 | struct cmd_ds_command *resp) | ||
412 | { | ||
413 | struct cmd_ds_802_11_rf_antenna *pAntenna = &resp->params.rant; | ||
414 | wlan_adapter *adapter = priv->adapter; | ||
415 | u16 action = le16_to_cpu(pAntenna->action); | ||
416 | |||
417 | if (action == cmd_act_get_rx) | ||
418 | adapter->rxantennamode = | ||
419 | le16_to_cpu(pAntenna->antennamode); | ||
420 | |||
421 | if (action == cmd_act_get_tx) | ||
422 | adapter->txantennamode = | ||
423 | le16_to_cpu(pAntenna->antennamode); | ||
424 | |||
425 | lbs_pr_debug(1, "RF_ANT_RESP: action = 0x%x, mode = 0x%04x\n", | ||
426 | action, le16_to_cpu(pAntenna->antennamode)); | ||
427 | |||
428 | return 0; | ||
429 | } | ||
430 | |||
431 | static int wlan_ret_802_11_rate_adapt_rateset(wlan_private * priv, | ||
432 | struct cmd_ds_command *resp) | ||
433 | { | ||
434 | struct cmd_ds_802_11_rate_adapt_rateset *rates = | ||
435 | &resp->params.rateset; | ||
436 | wlan_adapter *adapter = priv->adapter; | ||
437 | |||
438 | ENTER(); | ||
439 | |||
440 | if (rates->action == cmd_act_get) { | ||
441 | adapter->enablehwauto = rates->enablehwauto; | ||
442 | adapter->ratebitmap = rates->bitmap; | ||
443 | } | ||
444 | |||
445 | LEAVE(); | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int wlan_ret_802_11_data_rate(wlan_private * priv, | ||
451 | struct cmd_ds_command *resp) | ||
452 | { | ||
453 | struct cmd_ds_802_11_data_rate *pdatarate = &resp->params.drate; | ||
454 | wlan_adapter *adapter = priv->adapter; | ||
455 | u8 dot11datarate; | ||
456 | |||
457 | ENTER(); | ||
458 | |||
459 | lbs_dbg_hex("DATA_RATE_RESP: data_rate- ", | ||
460 | (u8 *) pdatarate, sizeof(struct cmd_ds_802_11_data_rate)); | ||
461 | |||
462 | dot11datarate = pdatarate->datarate[0]; | ||
463 | if (pdatarate->action == cmd_act_get_tx_rate) { | ||
464 | memcpy(adapter->libertas_supported_rates, pdatarate->datarate, | ||
465 | sizeof(adapter->libertas_supported_rates)); | ||
466 | } | ||
467 | adapter->datarate = libertas_index_to_data_rate(dot11datarate); | ||
468 | |||
469 | LEAVE(); | ||
470 | return 0; | ||
471 | } | ||
472 | |||
473 | static int wlan_ret_802_11_rf_channel(wlan_private * priv, | ||
474 | struct cmd_ds_command *resp) | ||
475 | { | ||
476 | struct cmd_ds_802_11_rf_channel *rfchannel = | ||
477 | &resp->params.rfchannel; | ||
478 | wlan_adapter *adapter = priv->adapter; | ||
479 | u16 action = le16_to_cpu(rfchannel->action); | ||
480 | u16 newchannel = le16_to_cpu(rfchannel->currentchannel); | ||
481 | |||
482 | ENTER(); | ||
483 | |||
484 | if (action == cmd_opt_802_11_rf_channel_get | ||
485 | && adapter->curbssparams.channel != newchannel) { | ||
486 | lbs_pr_debug(1, "channel Switch: %d to %d\n", | ||
487 | adapter->curbssparams.channel, newchannel); | ||
488 | |||
489 | /* Update the channel again */ | ||
490 | adapter->curbssparams.channel = newchannel; | ||
491 | } | ||
492 | |||
493 | LEAVE(); | ||
494 | return 0; | ||
495 | } | ||
496 | |||
497 | static int wlan_ret_802_11_rssi(wlan_private * priv, | ||
498 | struct cmd_ds_command *resp) | ||
499 | { | ||
500 | struct cmd_ds_802_11_rssi_rsp *rssirsp = &resp->params.rssirsp; | ||
501 | wlan_adapter *adapter = priv->adapter; | ||
502 | |||
503 | /* store the non average value */ | ||
504 | adapter->SNR[TYPE_BEACON][TYPE_NOAVG] = le16_to_cpu(rssirsp->SNR); | ||
505 | adapter->NF[TYPE_BEACON][TYPE_NOAVG] = | ||
506 | le16_to_cpu(rssirsp->noisefloor); | ||
507 | |||
508 | adapter->SNR[TYPE_BEACON][TYPE_AVG] = le16_to_cpu(rssirsp->avgSNR); | ||
509 | adapter->NF[TYPE_BEACON][TYPE_AVG] = | ||
510 | le16_to_cpu(rssirsp->avgnoisefloor); | ||
511 | |||
512 | adapter->RSSI[TYPE_BEACON][TYPE_NOAVG] = | ||
513 | CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], | ||
514 | adapter->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
515 | |||
516 | adapter->RSSI[TYPE_BEACON][TYPE_AVG] = | ||
517 | CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG] / AVG_SCALE, | ||
518 | adapter->NF[TYPE_BEACON][TYPE_AVG] / AVG_SCALE); | ||
519 | |||
520 | lbs_pr_debug(1, "Beacon RSSI value = 0x%x\n", | ||
521 | adapter->RSSI[TYPE_BEACON][TYPE_AVG]); | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static int wlan_ret_802_11_eeprom_access(wlan_private * priv, | ||
527 | struct cmd_ds_command *resp) | ||
528 | { | ||
529 | wlan_adapter *adapter = priv->adapter; | ||
530 | struct wlan_ioctl_regrdwr *pbuf; | ||
531 | pbuf = (struct wlan_ioctl_regrdwr *) adapter->prdeeprom; | ||
532 | |||
533 | lbs_pr_debug(1, "eeprom read len=%x\n", | ||
534 | le16_to_cpu(resp->params.rdeeprom.bytecount)); | ||
535 | if (pbuf->NOB < le16_to_cpu(resp->params.rdeeprom.bytecount)) { | ||
536 | pbuf->NOB = 0; | ||
537 | lbs_pr_debug(1, "eeprom read return length is too big\n"); | ||
538 | return -1; | ||
539 | } | ||
540 | pbuf->NOB = le16_to_cpu(resp->params.rdeeprom.bytecount); | ||
541 | if (pbuf->NOB > 0) { | ||
542 | |||
543 | memcpy(&pbuf->value, (u8 *) & resp->params.rdeeprom.value, | ||
544 | le16_to_cpu(resp->params.rdeeprom.bytecount)); | ||
545 | lbs_dbg_hex("adapter", (char *)&pbuf->value, | ||
546 | le16_to_cpu(resp->params.rdeeprom.bytecount)); | ||
547 | } | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int wlan_ret_get_log(wlan_private * priv, | ||
552 | struct cmd_ds_command *resp) | ||
553 | { | ||
554 | struct cmd_ds_802_11_get_log *logmessage = | ||
555 | (struct cmd_ds_802_11_get_log *)&resp->params.glog; | ||
556 | wlan_adapter *adapter = priv->adapter; | ||
557 | |||
558 | ENTER(); | ||
559 | |||
560 | /* TODO Convert it to Big Endian before copy */ | ||
561 | memcpy(&adapter->logmsg, logmessage, | ||
562 | sizeof(struct cmd_ds_802_11_get_log)); | ||
563 | |||
564 | LEAVE(); | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | static inline int handle_cmd_response(u16 respcmd, | ||
569 | struct cmd_ds_command *resp, | ||
570 | wlan_private *priv) | ||
571 | { | ||
572 | int ret = 0; | ||
573 | unsigned long flags; | ||
574 | wlan_adapter *adapter = priv->adapter; | ||
575 | |||
576 | switch (respcmd) { | ||
577 | case cmd_ret_mac_reg_access: | ||
578 | case cmd_ret_bbp_reg_access: | ||
579 | case cmd_ret_rf_reg_access: | ||
580 | ret = wlan_ret_reg_access(priv, respcmd, resp); | ||
581 | break; | ||
582 | |||
583 | case cmd_ret_hw_spec_info: | ||
584 | ret = wlan_ret_get_hw_spec(priv, resp); | ||
585 | break; | ||
586 | |||
587 | case cmd_ret_802_11_scan: | ||
588 | ret = libertas_ret_80211_scan(priv, resp); | ||
589 | break; | ||
590 | |||
591 | case cmd_ret_802_11_get_log: | ||
592 | ret = wlan_ret_get_log(priv, resp); | ||
593 | break; | ||
594 | |||
595 | case cmd_ret_802_11_associate: | ||
596 | case cmd_ret_802_11_reassociate: | ||
597 | ret = libertas_ret_80211_associate(priv, resp); | ||
598 | break; | ||
599 | |||
600 | case cmd_ret_802_11_disassociate: | ||
601 | case cmd_ret_802_11_deauthenticate: | ||
602 | ret = libertas_ret_80211_disassociate(priv, resp); | ||
603 | break; | ||
604 | |||
605 | case cmd_ret_802_11_ad_hoc_start: | ||
606 | case cmd_ret_802_11_ad_hoc_join: | ||
607 | ret = libertas_ret_80211_ad_hoc_start(priv, resp); | ||
608 | break; | ||
609 | |||
610 | case cmd_ret_802_11_stat: | ||
611 | ret = wlan_ret_802_11_stat(priv, resp); | ||
612 | break; | ||
613 | |||
614 | case cmd_ret_802_11_snmp_mib: | ||
615 | ret = wlan_ret_802_11_snmp_mib(priv, resp); | ||
616 | break; | ||
617 | |||
618 | case cmd_ret_802_11_rf_tx_power: | ||
619 | ret = wlan_ret_802_11_rf_tx_power(priv, resp); | ||
620 | break; | ||
621 | |||
622 | case cmd_ret_802_11_set_afc: | ||
623 | case cmd_ret_802_11_get_afc: | ||
624 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
625 | memmove(adapter->cur_cmd->pdata_buf, | ||
626 | &resp->params.afc, | ||
627 | sizeof(struct cmd_ds_802_11_afc)); | ||
628 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
629 | |||
630 | break; | ||
631 | case cmd_ret_802_11_rf_antenna: | ||
632 | ret = wlan_ret_802_11_rf_antenna(priv, resp); | ||
633 | break; | ||
634 | |||
635 | case cmd_ret_mac_multicast_adr: | ||
636 | case cmd_ret_mac_control: | ||
637 | case cmd_ret_802_11_set_wep: | ||
638 | case cmd_ret_802_11_reset: | ||
639 | case cmd_ret_802_11_authenticate: | ||
640 | case cmd_ret_802_11_radio_control: | ||
641 | case cmd_ret_802_11_beacon_stop: | ||
642 | case cmd_ret_802_11_enable_rsn: | ||
643 | break; | ||
644 | |||
645 | case cmd_ret_802_11_data_rate: | ||
646 | ret = wlan_ret_802_11_data_rate(priv, resp); | ||
647 | break; | ||
648 | case cmd_ret_802_11_rate_adapt_rateset: | ||
649 | ret = wlan_ret_802_11_rate_adapt_rateset(priv, resp); | ||
650 | break; | ||
651 | case cmd_ret_802_11_rf_channel: | ||
652 | ret = wlan_ret_802_11_rf_channel(priv, resp); | ||
653 | break; | ||
654 | |||
655 | case cmd_ret_802_11_rssi: | ||
656 | ret = wlan_ret_802_11_rssi(priv, resp); | ||
657 | break; | ||
658 | |||
659 | case cmd_ret_802_11_mac_address: | ||
660 | ret = wlan_ret_802_11_mac_address(priv, resp); | ||
661 | break; | ||
662 | |||
663 | case cmd_ret_802_11_ad_hoc_stop: | ||
664 | ret = libertas_ret_80211_ad_hoc_stop(priv, resp); | ||
665 | break; | ||
666 | |||
667 | case cmd_ret_802_11_key_material: | ||
668 | lbs_pr_debug(1, "CMD_RESP: KEY_MATERIAL command response\n"); | ||
669 | ret = wlan_ret_802_11_key_material(priv, resp); | ||
670 | break; | ||
671 | |||
672 | case cmd_ret_802_11_eeprom_access: | ||
673 | ret = wlan_ret_802_11_eeprom_access(priv, resp); | ||
674 | break; | ||
675 | |||
676 | case cmd_ret_802_11d_domain_info: | ||
677 | ret = libertas_ret_802_11d_domain_info(priv, resp); | ||
678 | break; | ||
679 | |||
680 | case cmd_ret_802_11_sleep_params: | ||
681 | ret = wlan_ret_802_11_sleep_params(priv, resp); | ||
682 | break; | ||
683 | case cmd_ret_802_11_inactivity_timeout: | ||
684 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
685 | *((u16 *) adapter->cur_cmd->pdata_buf) = | ||
686 | le16_to_cpu(resp->params.inactivity_timeout.timeout); | ||
687 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
688 | break; | ||
689 | |||
690 | case cmd_ret_802_11_tpc_cfg: | ||
691 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
692 | memmove(adapter->cur_cmd->pdata_buf, | ||
693 | &resp->params.tpccfg, | ||
694 | sizeof(struct cmd_ds_802_11_tpc_cfg)); | ||
695 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
696 | break; | ||
697 | case cmd_ret_802_11_led_gpio_ctrl: | ||
698 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
699 | memmove(adapter->cur_cmd->pdata_buf, | ||
700 | &resp->params.ledgpio, | ||
701 | sizeof(struct cmd_ds_802_11_led_ctrl)); | ||
702 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
703 | break; | ||
704 | case cmd_ret_802_11_pwr_cfg: | ||
705 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
706 | memmove(adapter->cur_cmd->pdata_buf, | ||
707 | &resp->params.pwrcfg, | ||
708 | sizeof(struct cmd_ds_802_11_pwr_cfg)); | ||
709 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
710 | |||
711 | break; | ||
712 | |||
713 | case cmd_ret_get_tsf: | ||
714 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
715 | memcpy(priv->adapter->cur_cmd->pdata_buf, | ||
716 | &resp->params.gettsf.tsfvalue, sizeof(u64)); | ||
717 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
718 | break; | ||
719 | case cmd_ret_bt_access: | ||
720 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
721 | if (adapter->cur_cmd->pdata_buf) | ||
722 | memcpy(adapter->cur_cmd->pdata_buf, | ||
723 | &resp->params.bt.addr1, 2 * ETH_ALEN); | ||
724 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
725 | break; | ||
726 | case cmd_ret_fwt_access: | ||
727 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
728 | if (adapter->cur_cmd->pdata_buf) | ||
729 | memcpy(adapter->cur_cmd->pdata_buf, | ||
730 | &resp->params.fwt, | ||
731 | sizeof(resp->params.fwt)); | ||
732 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
733 | break; | ||
734 | case cmd_ret_mesh_access: | ||
735 | if (adapter->cur_cmd->pdata_buf) | ||
736 | memcpy(adapter->cur_cmd->pdata_buf, | ||
737 | &resp->params.mesh, | ||
738 | sizeof(resp->params.mesh)); | ||
739 | break; | ||
740 | case cmd_rte_802_11_tx_rate_query: | ||
741 | priv->adapter->txrate = resp->params.txrate.txrate; | ||
742 | break; | ||
743 | default: | ||
744 | lbs_pr_debug(1, "CMD_RESP: Unknown command response %#x\n", | ||
745 | resp->command); | ||
746 | break; | ||
747 | } | ||
748 | return ret; | ||
749 | } | ||
750 | |||
751 | int libertas_process_rx_command(wlan_private * priv) | ||
752 | { | ||
753 | u16 respcmd; | ||
754 | struct cmd_ds_command *resp; | ||
755 | wlan_adapter *adapter = priv->adapter; | ||
756 | int ret = 0; | ||
757 | ulong flags; | ||
758 | u16 result; | ||
759 | |||
760 | ENTER(); | ||
761 | |||
762 | lbs_pr_debug(1, "CMD_RESP: @ %lu\n", jiffies); | ||
763 | |||
764 | /* Now we got response from FW, cancel the command timer */ | ||
765 | del_timer(&adapter->command_timer); | ||
766 | |||
767 | mutex_lock(&adapter->lock); | ||
768 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
769 | |||
770 | if (!adapter->cur_cmd) { | ||
771 | lbs_pr_debug(1, "CMD_RESP: NULL cur_cmd=%p\n", adapter->cur_cmd); | ||
772 | ret = -1; | ||
773 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
774 | goto done; | ||
775 | } | ||
776 | resp = (struct cmd_ds_command *)(adapter->cur_cmd->bufvirtualaddr); | ||
777 | |||
778 | lbs_dbg_hex("CMD_RESP:", adapter->cur_cmd->bufvirtualaddr, | ||
779 | priv->wlan_dev.upld_len); | ||
780 | |||
781 | respcmd = le16_to_cpu(resp->command); | ||
782 | |||
783 | result = le16_to_cpu(resp->result); | ||
784 | |||
785 | lbs_pr_debug(1, "CMD_RESP: %x result: %d length: %d\n", respcmd, | ||
786 | result, priv->wlan_dev.upld_len); | ||
787 | |||
788 | if (!(respcmd & 0x8000)) { | ||
789 | lbs_pr_debug(1, "Invalid response to command!"); | ||
790 | adapter->cur_cmd_retcode = -1; | ||
791 | __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); | ||
792 | adapter->nr_cmd_pending--; | ||
793 | adapter->cur_cmd = NULL; | ||
794 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
795 | ret = -1; | ||
796 | goto done; | ||
797 | } | ||
798 | |||
799 | /* Store the response code to cur_cmd_retcode. */ | ||
800 | adapter->cur_cmd_retcode = le16_to_cpu(resp->result); | ||
801 | |||
802 | if (respcmd == cmd_ret_802_11_ps_mode) { | ||
803 | struct cmd_ds_802_11_ps_mode *psmode; | ||
804 | |||
805 | psmode = &resp->params.psmode; | ||
806 | lbs_pr_debug(1, | ||
807 | "CMD_RESP: PS_MODE cmd reply result=%#x action=0x%X\n", | ||
808 | resp->result, psmode->action); | ||
809 | psmode->action = cpu_to_le16(psmode->action); | ||
810 | |||
811 | if (result) { | ||
812 | lbs_pr_debug(1, "CMD_RESP: PS command failed- %#x \n", | ||
813 | resp->result); | ||
814 | if (adapter->inframode == wlan802_11ibss) { | ||
815 | /* | ||
816 | * We should not re-try enter-ps command in | ||
817 | * ad-hoc mode. It takes place in | ||
818 | * libertas_execute_next_command(). | ||
819 | */ | ||
820 | if (psmode->action == cmd_subcmd_enter_ps) | ||
821 | adapter->psmode = | ||
822 | wlan802_11powermodecam; | ||
823 | } | ||
824 | } else if (psmode->action == cmd_subcmd_enter_ps) { | ||
825 | adapter->needtowakeup = 0; | ||
826 | adapter->psstate = PS_STATE_AWAKE; | ||
827 | |||
828 | lbs_pr_debug(1, "CMD_RESP: Enter_PS command response\n"); | ||
829 | if (adapter->connect_status != libertas_connected) { | ||
830 | /* | ||
831 | * When Deauth Event received before Enter_PS command | ||
832 | * response, We need to wake up the firmware. | ||
833 | */ | ||
834 | lbs_pr_debug(1, | ||
835 | "Disconnected, Going to invoke libertas_ps_wakeup\n"); | ||
836 | |||
837 | mutex_unlock(&adapter->lock); | ||
838 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
839 | libertas_ps_wakeup(priv, 0); | ||
840 | mutex_lock(&adapter->lock); | ||
841 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
842 | } | ||
843 | } else if (psmode->action == cmd_subcmd_exit_ps) { | ||
844 | adapter->needtowakeup = 0; | ||
845 | adapter->psstate = PS_STATE_FULL_POWER; | ||
846 | lbs_pr_debug(1, "CMD_RESP: Exit_PS command response\n"); | ||
847 | } else { | ||
848 | lbs_pr_debug(1, "CMD_RESP: PS- action=0x%X\n", | ||
849 | psmode->action); | ||
850 | } | ||
851 | |||
852 | __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); | ||
853 | adapter->nr_cmd_pending--; | ||
854 | adapter->cur_cmd = NULL; | ||
855 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
856 | |||
857 | ret = 0; | ||
858 | goto done; | ||
859 | } | ||
860 | |||
861 | if (adapter->cur_cmd->cmdflags & CMD_F_HOSTCMD) { | ||
862 | /* Copy the response back to response buffer */ | ||
863 | memcpy(adapter->cur_cmd->pdata_buf, resp, resp->size); | ||
864 | |||
865 | adapter->cur_cmd->cmdflags &= ~CMD_F_HOSTCMD; | ||
866 | } | ||
867 | |||
868 | /* If the command is not successful, cleanup and return failure */ | ||
869 | if ((result != 0 || !(respcmd & 0x8000))) { | ||
870 | lbs_pr_debug(1, "CMD_RESP: command reply %#x result=%#x\n", | ||
871 | resp->command, resp->result); | ||
872 | /* | ||
873 | * Handling errors here | ||
874 | */ | ||
875 | switch (respcmd) { | ||
876 | case cmd_ret_hw_spec_info: | ||
877 | case cmd_ret_802_11_reset: | ||
878 | lbs_pr_debug(1, "CMD_RESP: Reset command failed\n"); | ||
879 | break; | ||
880 | |||
881 | } | ||
882 | |||
883 | __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); | ||
884 | adapter->nr_cmd_pending--; | ||
885 | adapter->cur_cmd = NULL; | ||
886 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
887 | |||
888 | ret = -1; | ||
889 | goto done; | ||
890 | } | ||
891 | |||
892 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
893 | |||
894 | ret = handle_cmd_response(respcmd, resp, priv); | ||
895 | |||
896 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
897 | if (adapter->cur_cmd) { | ||
898 | /* Clean up and Put current command back to cmdfreeq */ | ||
899 | __libertas_cleanup_and_insert_cmd(priv, adapter->cur_cmd); | ||
900 | adapter->nr_cmd_pending--; | ||
901 | WARN_ON(adapter->nr_cmd_pending > 128); | ||
902 | adapter->cur_cmd = NULL; | ||
903 | } | ||
904 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
905 | |||
906 | done: | ||
907 | mutex_unlock(&adapter->lock); | ||
908 | LEAVE(); | ||
909 | return ret; | ||
910 | } | ||
911 | |||
912 | int libertas_process_event(wlan_private * priv) | ||
913 | { | ||
914 | int ret = 0; | ||
915 | wlan_adapter *adapter = priv->adapter; | ||
916 | u32 eventcause; | ||
917 | |||
918 | spin_lock_irq(&adapter->driver_lock); | ||
919 | eventcause = adapter->eventcause; | ||
920 | spin_unlock_irq(&adapter->driver_lock); | ||
921 | |||
922 | ENTER(); | ||
923 | |||
924 | lbs_pr_debug(1, "EVENT Cause %x\n", eventcause); | ||
925 | |||
926 | switch (eventcause >> SBI_EVENT_CAUSE_SHIFT) { | ||
927 | case MACREG_INT_CODE_LINK_SENSED: | ||
928 | lbs_pr_debug(1, "EVENT: MACREG_INT_CODE_LINK_SENSED\n"); | ||
929 | break; | ||
930 | |||
931 | case MACREG_INT_CODE_DEAUTHENTICATED: | ||
932 | lbs_pr_debug(1, "EVENT: Deauthenticated\n"); | ||
933 | libertas_mac_event_disconnected(priv); | ||
934 | break; | ||
935 | |||
936 | case MACREG_INT_CODE_DISASSOCIATED: | ||
937 | lbs_pr_debug(1, "EVENT: Disassociated\n"); | ||
938 | libertas_mac_event_disconnected(priv); | ||
939 | break; | ||
940 | |||
941 | case MACREG_INT_CODE_LINK_LOSE_NO_SCAN: | ||
942 | lbs_pr_debug(1, "EVENT: Link lost\n"); | ||
943 | libertas_mac_event_disconnected(priv); | ||
944 | break; | ||
945 | |||
946 | case MACREG_INT_CODE_PS_SLEEP: | ||
947 | lbs_pr_debug(1, "EVENT: SLEEP\n"); | ||
948 | lbs_pr_debug(1, "_"); | ||
949 | |||
950 | /* handle unexpected PS SLEEP event */ | ||
951 | if (adapter->psstate == PS_STATE_FULL_POWER) { | ||
952 | lbs_pr_debug(1, | ||
953 | "EVENT: In FULL POWER mode - ignore PS SLEEP\n"); | ||
954 | break; | ||
955 | } | ||
956 | adapter->psstate = PS_STATE_PRE_SLEEP; | ||
957 | |||
958 | libertas_ps_confirm_sleep(priv, (u16) adapter->psmode); | ||
959 | |||
960 | break; | ||
961 | |||
962 | case MACREG_INT_CODE_PS_AWAKE: | ||
963 | lbs_pr_debug(1, "EVENT: AWAKE \n"); | ||
964 | lbs_pr_debug(1, "|"); | ||
965 | |||
966 | /* handle unexpected PS AWAKE event */ | ||
967 | if (adapter->psstate == PS_STATE_FULL_POWER) { | ||
968 | lbs_pr_debug(1, | ||
969 | "EVENT: In FULL POWER mode - ignore PS AWAKE\n"); | ||
970 | break; | ||
971 | } | ||
972 | |||
973 | adapter->psstate = PS_STATE_AWAKE; | ||
974 | |||
975 | if (adapter->needtowakeup) { | ||
976 | /* | ||
977 | * wait for the command processing to finish | ||
978 | * before resuming sending | ||
979 | * adapter->needtowakeup will be set to FALSE | ||
980 | * in libertas_ps_wakeup() | ||
981 | */ | ||
982 | lbs_pr_debug(1, "Waking up...\n"); | ||
983 | libertas_ps_wakeup(priv, 0); | ||
984 | } | ||
985 | break; | ||
986 | |||
987 | case MACREG_INT_CODE_MIC_ERR_UNICAST: | ||
988 | lbs_pr_debug(1, "EVENT: UNICAST MIC ERROR\n"); | ||
989 | handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_UNICAST); | ||
990 | break; | ||
991 | |||
992 | case MACREG_INT_CODE_MIC_ERR_MULTICAST: | ||
993 | lbs_pr_debug(1, "EVENT: MULTICAST MIC ERROR\n"); | ||
994 | handle_mic_failureevent(priv, MACREG_INT_CODE_MIC_ERR_MULTICAST); | ||
995 | break; | ||
996 | case MACREG_INT_CODE_MIB_CHANGED: | ||
997 | case MACREG_INT_CODE_INIT_DONE: | ||
998 | break; | ||
999 | |||
1000 | case MACREG_INT_CODE_ADHOC_BCN_LOST: | ||
1001 | lbs_pr_debug(1, "EVENT: HWAC - ADHOC BCN LOST\n"); | ||
1002 | break; | ||
1003 | |||
1004 | case MACREG_INT_CODE_RSSI_LOW: | ||
1005 | lbs_pr_alert( "EVENT: RSSI_LOW\n"); | ||
1006 | break; | ||
1007 | case MACREG_INT_CODE_SNR_LOW: | ||
1008 | lbs_pr_alert( "EVENT: SNR_LOW\n"); | ||
1009 | break; | ||
1010 | case MACREG_INT_CODE_MAX_FAIL: | ||
1011 | lbs_pr_alert( "EVENT: MAX_FAIL\n"); | ||
1012 | break; | ||
1013 | case MACREG_INT_CODE_RSSI_HIGH: | ||
1014 | lbs_pr_alert( "EVENT: RSSI_HIGH\n"); | ||
1015 | break; | ||
1016 | case MACREG_INT_CODE_SNR_HIGH: | ||
1017 | lbs_pr_alert( "EVENT: SNR_HIGH\n"); | ||
1018 | break; | ||
1019 | |||
1020 | default: | ||
1021 | lbs_pr_alert( "EVENT: unknown event id: %#x\n", | ||
1022 | eventcause >> SBI_EVENT_CAUSE_SHIFT); | ||
1023 | break; | ||
1024 | } | ||
1025 | |||
1026 | spin_lock_irq(&adapter->driver_lock); | ||
1027 | adapter->eventcause = 0; | ||
1028 | spin_unlock_irq(&adapter->driver_lock); | ||
1029 | LEAVE(); | ||
1030 | return ret; | ||
1031 | } | ||
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c new file mode 100644 index 000000000000..51dfd202f558 --- /dev/null +++ b/drivers/net/wireless/libertas/debugfs.c | |||
@@ -0,0 +1,1935 @@ | |||
1 | #include <linux/module.h> | ||
2 | #include <linux/dcache.h> | ||
3 | #include <linux/debugfs.h> | ||
4 | #include <linux/delay.h> | ||
5 | #include <linux/mm.h> | ||
6 | #include <net/iw_handler.h> | ||
7 | #include "dev.h" | ||
8 | #include "decl.h" | ||
9 | #include "host.h" | ||
10 | |||
11 | static struct dentry *libertas_dir = NULL; | ||
12 | static char *szStates[] = { | ||
13 | "Connected", | ||
14 | "Disconnected" | ||
15 | }; | ||
16 | |||
17 | void libertas_debug_init(wlan_private * priv, struct net_device *dev); | ||
18 | |||
19 | static int open_file_generic(struct inode *inode, struct file *file) | ||
20 | { | ||
21 | file->private_data = inode->i_private; | ||
22 | return 0; | ||
23 | } | ||
24 | |||
25 | static ssize_t write_file_dummy(struct file *file, const char __user *buf, | ||
26 | size_t count, loff_t *ppos) | ||
27 | { | ||
28 | return -EINVAL; | ||
29 | } | ||
30 | |||
31 | static const size_t len = PAGE_SIZE; | ||
32 | |||
33 | static ssize_t libertas_dev_info(struct file *file, char __user *userbuf, | ||
34 | size_t count, loff_t *ppos) | ||
35 | { | ||
36 | wlan_private *priv = file->private_data; | ||
37 | size_t pos = 0; | ||
38 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
39 | char *buf = (char *)addr; | ||
40 | ssize_t res; | ||
41 | |||
42 | pos += snprintf(buf+pos, len-pos, "state = %s\n", | ||
43 | szStates[priv->adapter->connect_status]); | ||
44 | pos += snprintf(buf+pos, len-pos, "region_code = %02x\n", | ||
45 | (u32) priv->adapter->regioncode); | ||
46 | |||
47 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
48 | |||
49 | free_page(addr); | ||
50 | return res; | ||
51 | } | ||
52 | |||
53 | |||
54 | static ssize_t libertas_getscantable(struct file *file, char __user *userbuf, | ||
55 | size_t count, loff_t *ppos) | ||
56 | { | ||
57 | wlan_private *priv = file->private_data; | ||
58 | size_t pos = 0; | ||
59 | int numscansdone = 0, res; | ||
60 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
61 | char *buf = (char *)addr; | ||
62 | |||
63 | pos += snprintf(buf+pos, len-pos, | ||
64 | "---------------------------------------"); | ||
65 | pos += snprintf(buf+pos, len-pos, | ||
66 | "---------------------------------------\n"); | ||
67 | pos += snprintf(buf+pos, len-pos, | ||
68 | "# | ch | ss | bssid | cap | TSF | Qual | SSID \n"); | ||
69 | pos += snprintf(buf+pos, len-pos, | ||
70 | "---------------------------------------"); | ||
71 | pos += snprintf(buf+pos, len-pos, | ||
72 | "---------------------------------------\n"); | ||
73 | |||
74 | while (numscansdone < priv->adapter->numinscantable) { | ||
75 | struct bss_descriptor *pbssinfo; | ||
76 | u16 cap; | ||
77 | |||
78 | pbssinfo = &priv->adapter->scantable[numscansdone]; | ||
79 | memcpy(&cap, &pbssinfo->cap, sizeof(cap)); | ||
80 | pos += snprintf(buf+pos, len-pos, | ||
81 | "%02u| %03d | %03ld | %02x:%02x:%02x:%02x:%02x:%02x |", | ||
82 | numscansdone, pbssinfo->channel, pbssinfo->rssi, | ||
83 | pbssinfo->macaddress[0], pbssinfo->macaddress[1], | ||
84 | pbssinfo->macaddress[2], pbssinfo->macaddress[3], | ||
85 | pbssinfo->macaddress[4], pbssinfo->macaddress[5]); | ||
86 | pos += snprintf(buf+pos, len-pos, " %04x-", cap); | ||
87 | pos += snprintf(buf+pos, len-pos, "%c%c%c |", | ||
88 | pbssinfo->cap.ibss ? 'A' : 'I', | ||
89 | pbssinfo->cap.privacy ? 'P' : ' ', | ||
90 | pbssinfo->cap.spectrummgmt ? 'S' : ' '); | ||
91 | pos += snprintf(buf+pos, len-pos, " %08llx |", pbssinfo->networktsf); | ||
92 | pos += snprintf(buf+pos, len-pos, " %d |", | ||
93 | SCAN_RSSI(priv->adapter->scantable[numscansdone].rssi)); | ||
94 | |||
95 | pos += snprintf(buf+pos, len-pos, " %s\n", pbssinfo->ssid.ssid); | ||
96 | |||
97 | numscansdone++; | ||
98 | } | ||
99 | |||
100 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
101 | |||
102 | free_page(addr); | ||
103 | return res; | ||
104 | } | ||
105 | |||
106 | static ssize_t libertas_sleepparams_write(struct file *file, | ||
107 | const char __user *user_buf, size_t count, | ||
108 | loff_t *ppos) | ||
109 | { | ||
110 | wlan_private *priv = file->private_data; | ||
111 | ssize_t buf_size, res; | ||
112 | int p1, p2, p3, p4, p5, p6; | ||
113 | struct sleep_params sp; | ||
114 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
115 | char *buf = (char *)addr; | ||
116 | |||
117 | buf_size = min(count, len - 1); | ||
118 | if (copy_from_user(buf, user_buf, buf_size)) { | ||
119 | res = -EFAULT; | ||
120 | goto out_unlock; | ||
121 | } | ||
122 | res = sscanf(buf, "%d %d %d %d %d %d", &p1, &p2, &p3, &p4, &p5, &p6); | ||
123 | if (res != 6) { | ||
124 | res = -EFAULT; | ||
125 | goto out_unlock; | ||
126 | } | ||
127 | sp.sp_error = p1; | ||
128 | sp.sp_offset = p2; | ||
129 | sp.sp_stabletime = p3; | ||
130 | sp.sp_calcontrol = p4; | ||
131 | sp.sp_extsleepclk = p5; | ||
132 | sp.sp_reserved = p6; | ||
133 | |||
134 | memcpy(&priv->adapter->sp, &sp, sizeof(struct sleep_params)); | ||
135 | |||
136 | res = libertas_prepare_and_send_command(priv, | ||
137 | cmd_802_11_sleep_params, | ||
138 | cmd_act_set, | ||
139 | cmd_option_waitforrsp, 0, NULL); | ||
140 | |||
141 | if (!res) | ||
142 | res = count; | ||
143 | else | ||
144 | res = -EINVAL; | ||
145 | |||
146 | out_unlock: | ||
147 | free_page(addr); | ||
148 | return res; | ||
149 | } | ||
150 | |||
151 | static ssize_t libertas_sleepparams_read(struct file *file, char __user *userbuf, | ||
152 | size_t count, loff_t *ppos) | ||
153 | { | ||
154 | wlan_private *priv = file->private_data; | ||
155 | wlan_adapter *adapter = priv->adapter; | ||
156 | ssize_t res; | ||
157 | size_t pos = 0; | ||
158 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
159 | char *buf = (char *)addr; | ||
160 | |||
161 | res = libertas_prepare_and_send_command(priv, | ||
162 | cmd_802_11_sleep_params, | ||
163 | cmd_act_get, | ||
164 | cmd_option_waitforrsp, 0, NULL); | ||
165 | if (res) { | ||
166 | res = -EFAULT; | ||
167 | goto out_unlock; | ||
168 | } | ||
169 | |||
170 | pos += snprintf(buf, len, "%d %d %d %d %d %d\n", adapter->sp.sp_error, | ||
171 | adapter->sp.sp_offset, adapter->sp.sp_stabletime, | ||
172 | adapter->sp.sp_calcontrol, adapter->sp.sp_extsleepclk, | ||
173 | adapter->sp.sp_reserved); | ||
174 | |||
175 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
176 | |||
177 | out_unlock: | ||
178 | free_page(addr); | ||
179 | return res; | ||
180 | } | ||
181 | |||
182 | static ssize_t libertas_extscan(struct file *file, const char __user *userbuf, | ||
183 | size_t count, loff_t *ppos) | ||
184 | { | ||
185 | wlan_private *priv = file->private_data; | ||
186 | ssize_t res, buf_size; | ||
187 | struct WLAN_802_11_SSID extscan_ssid; | ||
188 | union iwreq_data wrqu; | ||
189 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
190 | char *buf = (char *)addr; | ||
191 | |||
192 | buf_size = min(count, len - 1); | ||
193 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
194 | res = -EFAULT; | ||
195 | goto out_unlock; | ||
196 | } | ||
197 | |||
198 | memcpy(&extscan_ssid.ssid, buf, strlen(buf)-1); | ||
199 | extscan_ssid.ssidlength = strlen(buf)-1; | ||
200 | |||
201 | libertas_send_specific_SSID_scan(priv, &extscan_ssid, 1); | ||
202 | |||
203 | memset(&wrqu, 0, sizeof(union iwreq_data)); | ||
204 | wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL); | ||
205 | |||
206 | out_unlock: | ||
207 | free_page(addr); | ||
208 | return count; | ||
209 | } | ||
210 | |||
211 | static int libertas_parse_chan(char *buf, size_t count, | ||
212 | struct wlan_ioctl_user_scan_cfg *scan_cfg, int dur) | ||
213 | { | ||
214 | char *start, *end, *hold, *str; | ||
215 | int i = 0; | ||
216 | |||
217 | start = strstr(buf, "chan="); | ||
218 | if (!start) | ||
219 | return -EINVAL; | ||
220 | start += 5; | ||
221 | end = strstr(start, " "); | ||
222 | if (!end) | ||
223 | end = buf + count; | ||
224 | hold = kzalloc((end - start)+1, GFP_KERNEL); | ||
225 | if (!hold) | ||
226 | return -ENOMEM; | ||
227 | strncpy(hold, start, end - start); | ||
228 | hold[(end-start)+1] = '\0'; | ||
229 | while(hold && (str = strsep(&hold, ","))) { | ||
230 | int chan; | ||
231 | char band, passive = 0; | ||
232 | sscanf(str, "%d%c%c", &chan, &band, &passive); | ||
233 | scan_cfg->chanlist[i].channumber = chan; | ||
234 | scan_cfg->chanlist[i].scantype = passive ? 1 : 0; | ||
235 | if (band == 'b' || band == 'g') | ||
236 | scan_cfg->chanlist[i].radiotype = 0; | ||
237 | else if (band == 'a') | ||
238 | scan_cfg->chanlist[i].radiotype = 1; | ||
239 | |||
240 | scan_cfg->chanlist[i].scantime = dur; | ||
241 | i++; | ||
242 | } | ||
243 | |||
244 | kfree(hold); | ||
245 | return i; | ||
246 | } | ||
247 | |||
248 | static void libertas_parse_bssid(char *buf, size_t count, | ||
249 | struct wlan_ioctl_user_scan_cfg *scan_cfg) | ||
250 | { | ||
251 | char *hold; | ||
252 | unsigned int mac[ETH_ALEN]; | ||
253 | int i; | ||
254 | |||
255 | hold = strstr(buf, "bssid="); | ||
256 | if (!hold) | ||
257 | return; | ||
258 | hold += 6; | ||
259 | sscanf(hold, "%2x:%2x:%2x:%2x:%2x:%2x", mac, mac+1, mac+2, mac+3, | ||
260 | mac+4, mac+5); | ||
261 | for(i=0;i<ETH_ALEN;i++) | ||
262 | scan_cfg->specificBSSID[i] = mac[i]; | ||
263 | } | ||
264 | |||
265 | static void libertas_parse_ssid(char *buf, size_t count, | ||
266 | struct wlan_ioctl_user_scan_cfg *scan_cfg) | ||
267 | { | ||
268 | char *hold, *end; | ||
269 | ssize_t size; | ||
270 | |||
271 | hold = strstr(buf, "ssid="); | ||
272 | if (!hold) | ||
273 | return; | ||
274 | hold += 5; | ||
275 | end = strstr(hold, " "); | ||
276 | if (!end) | ||
277 | end = buf + count - 1; | ||
278 | |||
279 | size = min(IW_ESSID_MAX_SIZE, end - hold); | ||
280 | strncpy(scan_cfg->specificSSID, hold, size); | ||
281 | |||
282 | return; | ||
283 | } | ||
284 | |||
285 | static void libertas_parse_keep(char *buf, size_t count, | ||
286 | struct wlan_ioctl_user_scan_cfg *scan_cfg) | ||
287 | { | ||
288 | char *hold; | ||
289 | int val; | ||
290 | |||
291 | hold = strstr(buf, "keep="); | ||
292 | if (!hold) | ||
293 | return; | ||
294 | hold += 5; | ||
295 | sscanf(hold, "%d", &val); | ||
296 | |||
297 | if (val != 0) | ||
298 | val = 1; | ||
299 | |||
300 | scan_cfg->keeppreviousscan = val; | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | static int libertas_parse_dur(char *buf, size_t count, | ||
305 | struct wlan_ioctl_user_scan_cfg *scan_cfg) | ||
306 | { | ||
307 | char *hold; | ||
308 | int val; | ||
309 | |||
310 | hold = strstr(buf, "dur="); | ||
311 | if (!hold) | ||
312 | return 0; | ||
313 | hold += 4; | ||
314 | sscanf(hold, "%d", &val); | ||
315 | |||
316 | return val; | ||
317 | } | ||
318 | |||
319 | static void libertas_parse_probes(char *buf, size_t count, | ||
320 | struct wlan_ioctl_user_scan_cfg *scan_cfg) | ||
321 | { | ||
322 | char *hold; | ||
323 | int val; | ||
324 | |||
325 | hold = strstr(buf, "probes="); | ||
326 | if (!hold) | ||
327 | return; | ||
328 | hold += 7; | ||
329 | sscanf(hold, "%d", &val); | ||
330 | |||
331 | scan_cfg->numprobes = val; | ||
332 | |||
333 | return; | ||
334 | } | ||
335 | |||
336 | static void libertas_parse_type(char *buf, size_t count, | ||
337 | struct wlan_ioctl_user_scan_cfg *scan_cfg) | ||
338 | { | ||
339 | char *hold; | ||
340 | int val; | ||
341 | |||
342 | hold = strstr(buf, "type="); | ||
343 | if (!hold) | ||
344 | return; | ||
345 | hold += 5; | ||
346 | sscanf(hold, "%d", &val); | ||
347 | |||
348 | /* type=1,2 or 3 */ | ||
349 | if (val < 1 || val > 3) | ||
350 | return; | ||
351 | |||
352 | scan_cfg->bsstype = val; | ||
353 | |||
354 | return; | ||
355 | } | ||
356 | |||
357 | static ssize_t libertas_setuserscan(struct file *file, | ||
358 | const char __user *userbuf, | ||
359 | size_t count, loff_t *ppos) | ||
360 | { | ||
361 | wlan_private *priv = file->private_data; | ||
362 | ssize_t res, buf_size; | ||
363 | struct wlan_ioctl_user_scan_cfg *scan_cfg; | ||
364 | union iwreq_data wrqu; | ||
365 | int dur; | ||
366 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
367 | char *buf = (char *)addr; | ||
368 | |||
369 | scan_cfg = kzalloc(sizeof(struct wlan_ioctl_user_scan_cfg), GFP_KERNEL); | ||
370 | if (!scan_cfg) | ||
371 | return -ENOMEM; | ||
372 | |||
373 | buf_size = min(count, len - 1); | ||
374 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
375 | res = -EFAULT; | ||
376 | goto out_unlock; | ||
377 | } | ||
378 | |||
379 | scan_cfg->bsstype = WLAN_SCAN_BSS_TYPE_ANY; | ||
380 | |||
381 | dur = libertas_parse_dur(buf, count, scan_cfg); | ||
382 | libertas_parse_chan(buf, count, scan_cfg, dur); | ||
383 | libertas_parse_bssid(buf, count, scan_cfg); | ||
384 | libertas_parse_ssid(buf, count, scan_cfg); | ||
385 | libertas_parse_keep(buf, count, scan_cfg); | ||
386 | libertas_parse_probes(buf, count, scan_cfg); | ||
387 | libertas_parse_type(buf, count, scan_cfg); | ||
388 | |||
389 | wlan_scan_networks(priv, scan_cfg); | ||
390 | wait_event_interruptible(priv->adapter->cmd_pending, | ||
391 | !priv->adapter->nr_cmd_pending); | ||
392 | |||
393 | memset(&wrqu, 0x00, sizeof(union iwreq_data)); | ||
394 | wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, NULL); | ||
395 | |||
396 | out_unlock: | ||
397 | free_page(addr); | ||
398 | kfree(scan_cfg); | ||
399 | return count; | ||
400 | } | ||
401 | |||
402 | static int libertas_event_initcmd(wlan_private *priv, void **response_buf, | ||
403 | struct cmd_ctrl_node **cmdnode, | ||
404 | struct cmd_ds_command **cmd) | ||
405 | { | ||
406 | u16 wait_option = cmd_option_waitforrsp; | ||
407 | |||
408 | if (!(*cmdnode = libertas_get_free_cmd_ctrl_node(priv))) { | ||
409 | lbs_pr_debug(1, "failed libertas_get_free_cmd_ctrl_node\n"); | ||
410 | return -ENOMEM; | ||
411 | } | ||
412 | if (!(*response_buf = kmalloc(3000, GFP_KERNEL))) { | ||
413 | lbs_pr_debug(1, "failed to allocate response buffer!\n"); | ||
414 | return -ENOMEM; | ||
415 | } | ||
416 | libertas_set_cmd_ctrl_node(priv, *cmdnode, 0, wait_option, NULL); | ||
417 | init_waitqueue_head(&(*cmdnode)->cmdwait_q); | ||
418 | (*cmdnode)->pdata_buf = *response_buf; | ||
419 | (*cmdnode)->cmdflags |= CMD_F_HOSTCMD; | ||
420 | (*cmdnode)->cmdwaitqwoken = 0; | ||
421 | *cmd = (struct cmd_ds_command *)(*cmdnode)->bufvirtualaddr; | ||
422 | (*cmd)->command = cmd_802_11_subscribe_event; | ||
423 | (*cmd)->seqnum = ++priv->adapter->seqnum; | ||
424 | (*cmd)->result = 0; | ||
425 | return 0; | ||
426 | } | ||
427 | |||
428 | static ssize_t libertas_lowrssi_read(struct file *file, char __user *userbuf, | ||
429 | size_t count, loff_t *ppos) | ||
430 | { | ||
431 | wlan_private *priv = file->private_data; | ||
432 | wlan_adapter *adapter = priv->adapter; | ||
433 | struct cmd_ctrl_node *pcmdnode; | ||
434 | struct cmd_ds_command *pcmdptr; | ||
435 | struct cmd_ds_802_11_subscribe_event *event; | ||
436 | void *response_buf; | ||
437 | int res, cmd_len; | ||
438 | ssize_t pos = 0; | ||
439 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
440 | char *buf = (char *)addr; | ||
441 | |||
442 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
443 | if (res < 0) { | ||
444 | free_page(addr); | ||
445 | return res; | ||
446 | } | ||
447 | |||
448 | event = &pcmdptr->params.subscribe_event; | ||
449 | event->action = cmd_act_get; | ||
450 | pcmdptr->size = | ||
451 | cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); | ||
452 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
453 | wake_up_interruptible(&priv->mainthread.waitq); | ||
454 | |||
455 | /* Sleep until response is generated by FW */ | ||
456 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
457 | pcmdnode->cmdwaitqwoken); | ||
458 | |||
459 | pcmdptr = response_buf; | ||
460 | if (pcmdptr->result) { | ||
461 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
462 | pcmdptr->result); | ||
463 | kfree(response_buf); | ||
464 | free_page(addr); | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
469 | lbs_pr_err("command response incorrect!\n"); | ||
470 | kfree(response_buf); | ||
471 | free_page(addr); | ||
472 | return 0; | ||
473 | } | ||
474 | |||
475 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
476 | event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); | ||
477 | while (cmd_len < pcmdptr->size) { | ||
478 | struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); | ||
479 | switch(header->type) { | ||
480 | struct mrvlietypes_rssithreshold *Lowrssi; | ||
481 | case TLV_TYPE_RSSI_LOW: | ||
482 | Lowrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len); | ||
483 | pos += snprintf(buf+pos, len-pos, "%d %d %d\n", | ||
484 | Lowrssi->rssivalue, | ||
485 | Lowrssi->rssifreq, | ||
486 | (event->events & 0x0001)?1:0); | ||
487 | default: | ||
488 | cmd_len += sizeof(struct mrvlietypes_snrthreshold); | ||
489 | break; | ||
490 | } | ||
491 | } | ||
492 | |||
493 | kfree(response_buf); | ||
494 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
495 | free_page(addr); | ||
496 | return res; | ||
497 | } | ||
498 | |||
499 | static u16 libertas_get_events_bitmap(wlan_private *priv) | ||
500 | { | ||
501 | wlan_adapter *adapter = priv->adapter; | ||
502 | struct cmd_ctrl_node *pcmdnode; | ||
503 | struct cmd_ds_command *pcmdptr; | ||
504 | struct cmd_ds_802_11_subscribe_event *event; | ||
505 | void *response_buf; | ||
506 | int res; | ||
507 | u16 event_bitmap; | ||
508 | |||
509 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
510 | if (res < 0) | ||
511 | return res; | ||
512 | |||
513 | event = &pcmdptr->params.subscribe_event; | ||
514 | event->action = cmd_act_get; | ||
515 | pcmdptr->size = | ||
516 | cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); | ||
517 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
518 | wake_up_interruptible(&priv->mainthread.waitq); | ||
519 | |||
520 | /* Sleep until response is generated by FW */ | ||
521 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
522 | pcmdnode->cmdwaitqwoken); | ||
523 | |||
524 | pcmdptr = response_buf; | ||
525 | |||
526 | if (pcmdptr->result) { | ||
527 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
528 | pcmdptr->result); | ||
529 | kfree(response_buf); | ||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
534 | lbs_pr_err("command response incorrect!\n"); | ||
535 | kfree(response_buf); | ||
536 | return 0; | ||
537 | } | ||
538 | |||
539 | event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); | ||
540 | event_bitmap = event->events; | ||
541 | kfree(response_buf); | ||
542 | return event_bitmap; | ||
543 | } | ||
544 | |||
545 | static ssize_t libertas_lowrssi_write(struct file *file, | ||
546 | const char __user *userbuf, | ||
547 | size_t count, loff_t *ppos) | ||
548 | { | ||
549 | wlan_private *priv = file->private_data; | ||
550 | wlan_adapter *adapter = priv->adapter; | ||
551 | ssize_t res, buf_size; | ||
552 | int value, freq, subscribed, cmd_len; | ||
553 | struct cmd_ctrl_node *pcmdnode; | ||
554 | struct cmd_ds_command *pcmdptr; | ||
555 | struct cmd_ds_802_11_subscribe_event *event; | ||
556 | struct mrvlietypes_rssithreshold *rssi_threshold; | ||
557 | void *response_buf; | ||
558 | u16 event_bitmap; | ||
559 | u8 *ptr; | ||
560 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
561 | char *buf = (char *)addr; | ||
562 | |||
563 | buf_size = min(count, len - 1); | ||
564 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
565 | res = -EFAULT; | ||
566 | goto out_unlock; | ||
567 | } | ||
568 | res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); | ||
569 | if (res != 3) { | ||
570 | res = -EFAULT; | ||
571 | goto out_unlock; | ||
572 | } | ||
573 | |||
574 | event_bitmap = libertas_get_events_bitmap(priv); | ||
575 | |||
576 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
577 | if (res < 0) | ||
578 | goto out_unlock; | ||
579 | |||
580 | event = &pcmdptr->params.subscribe_event; | ||
581 | event->action = cmd_act_set; | ||
582 | pcmdptr->size = cpu_to_le16(S_DS_GEN + | ||
583 | sizeof(struct cmd_ds_802_11_subscribe_event) + | ||
584 | sizeof(struct mrvlietypes_rssithreshold)); | ||
585 | |||
586 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
587 | ptr = (u8*) pcmdptr+cmd_len; | ||
588 | rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr); | ||
589 | rssi_threshold->header.type = cpu_to_le16(0x0104); | ||
590 | rssi_threshold->header.len = 2; | ||
591 | rssi_threshold->rssivalue = cpu_to_le16(value); | ||
592 | rssi_threshold->rssifreq = cpu_to_le16(freq); | ||
593 | event_bitmap |= subscribed ? 0x0001 : 0x0; | ||
594 | event->events = event_bitmap; | ||
595 | |||
596 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
597 | wake_up_interruptible(&priv->mainthread.waitq); | ||
598 | |||
599 | /* Sleep until response is generated by FW */ | ||
600 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
601 | pcmdnode->cmdwaitqwoken); | ||
602 | |||
603 | pcmdptr = response_buf; | ||
604 | |||
605 | if (pcmdptr->result) { | ||
606 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
607 | pcmdptr->result); | ||
608 | kfree(response_buf); | ||
609 | free_page(addr); | ||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
614 | lbs_pr_err("command response incorrect!\n"); | ||
615 | kfree(response_buf); | ||
616 | free_page(addr); | ||
617 | return 0; | ||
618 | } | ||
619 | |||
620 | res = count; | ||
621 | out_unlock: | ||
622 | free_page(addr); | ||
623 | return res; | ||
624 | } | ||
625 | |||
626 | static ssize_t libertas_lowsnr_read(struct file *file, char __user *userbuf, | ||
627 | size_t count, loff_t *ppos) | ||
628 | { | ||
629 | wlan_private *priv = file->private_data; | ||
630 | wlan_adapter *adapter = priv->adapter; | ||
631 | struct cmd_ctrl_node *pcmdnode; | ||
632 | struct cmd_ds_command *pcmdptr; | ||
633 | struct cmd_ds_802_11_subscribe_event *event; | ||
634 | void *response_buf; | ||
635 | int res, cmd_len; | ||
636 | ssize_t pos = 0; | ||
637 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
638 | char *buf = (char *)addr; | ||
639 | |||
640 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
641 | if (res < 0) { | ||
642 | free_page(addr); | ||
643 | return res; | ||
644 | } | ||
645 | |||
646 | event = &pcmdptr->params.subscribe_event; | ||
647 | event->action = cmd_act_get; | ||
648 | pcmdptr->size = | ||
649 | cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); | ||
650 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
651 | wake_up_interruptible(&priv->mainthread.waitq); | ||
652 | |||
653 | /* Sleep until response is generated by FW */ | ||
654 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
655 | pcmdnode->cmdwaitqwoken); | ||
656 | |||
657 | pcmdptr = response_buf; | ||
658 | |||
659 | if (pcmdptr->result) { | ||
660 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
661 | pcmdptr->result); | ||
662 | kfree(response_buf); | ||
663 | free_page(addr); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
668 | lbs_pr_err("command response incorrect!\n"); | ||
669 | kfree(response_buf); | ||
670 | free_page(addr); | ||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
675 | event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); | ||
676 | while (cmd_len < pcmdptr->size) { | ||
677 | struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); | ||
678 | switch(header->type) { | ||
679 | struct mrvlietypes_snrthreshold *LowSnr; | ||
680 | case TLV_TYPE_SNR_LOW: | ||
681 | LowSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len); | ||
682 | pos += snprintf(buf+pos, len-pos, "%d %d %d\n", | ||
683 | LowSnr->snrvalue, | ||
684 | LowSnr->snrfreq, | ||
685 | (event->events & 0x0002)?1:0); | ||
686 | default: | ||
687 | cmd_len += sizeof(struct mrvlietypes_snrthreshold); | ||
688 | break; | ||
689 | } | ||
690 | } | ||
691 | |||
692 | kfree(response_buf); | ||
693 | |||
694 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
695 | free_page(addr); | ||
696 | return res; | ||
697 | } | ||
698 | |||
699 | static ssize_t libertas_lowsnr_write(struct file *file, | ||
700 | const char __user *userbuf, | ||
701 | size_t count, loff_t *ppos) | ||
702 | { | ||
703 | wlan_private *priv = file->private_data; | ||
704 | wlan_adapter *adapter = priv->adapter; | ||
705 | ssize_t res, buf_size; | ||
706 | int value, freq, subscribed, cmd_len; | ||
707 | struct cmd_ctrl_node *pcmdnode; | ||
708 | struct cmd_ds_command *pcmdptr; | ||
709 | struct cmd_ds_802_11_subscribe_event *event; | ||
710 | struct mrvlietypes_snrthreshold *snr_threshold; | ||
711 | void *response_buf; | ||
712 | u16 event_bitmap; | ||
713 | u8 *ptr; | ||
714 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
715 | char *buf = (char *)addr; | ||
716 | |||
717 | buf_size = min(count, len - 1); | ||
718 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
719 | res = -EFAULT; | ||
720 | goto out_unlock; | ||
721 | } | ||
722 | res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); | ||
723 | if (res != 3) { | ||
724 | res = -EFAULT; | ||
725 | goto out_unlock; | ||
726 | } | ||
727 | |||
728 | event_bitmap = libertas_get_events_bitmap(priv); | ||
729 | |||
730 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
731 | if (res < 0) | ||
732 | goto out_unlock; | ||
733 | |||
734 | event = &pcmdptr->params.subscribe_event; | ||
735 | event->action = cmd_act_set; | ||
736 | pcmdptr->size = cpu_to_le16(S_DS_GEN + | ||
737 | sizeof(struct cmd_ds_802_11_subscribe_event) + | ||
738 | sizeof(struct mrvlietypes_snrthreshold)); | ||
739 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
740 | ptr = (u8*) pcmdptr+cmd_len; | ||
741 | snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr); | ||
742 | snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_LOW); | ||
743 | snr_threshold->header.len = 2; | ||
744 | snr_threshold->snrvalue = cpu_to_le16(value); | ||
745 | snr_threshold->snrfreq = cpu_to_le16(freq); | ||
746 | event_bitmap |= subscribed ? 0x0002 : 0x0; | ||
747 | event->events = event_bitmap; | ||
748 | |||
749 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
750 | wake_up_interruptible(&priv->mainthread.waitq); | ||
751 | |||
752 | /* Sleep until response is generated by FW */ | ||
753 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
754 | pcmdnode->cmdwaitqwoken); | ||
755 | |||
756 | pcmdptr = response_buf; | ||
757 | |||
758 | if (pcmdptr->result) { | ||
759 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
760 | pcmdptr->result); | ||
761 | kfree(response_buf); | ||
762 | free_page(addr); | ||
763 | return 0; | ||
764 | } | ||
765 | |||
766 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
767 | lbs_pr_err("command response incorrect!\n"); | ||
768 | kfree(response_buf); | ||
769 | free_page(addr); | ||
770 | return 0; | ||
771 | } | ||
772 | |||
773 | res = count; | ||
774 | |||
775 | out_unlock: | ||
776 | free_page(addr); | ||
777 | return res; | ||
778 | } | ||
779 | |||
780 | static ssize_t libertas_failcount_read(struct file *file, char __user *userbuf, | ||
781 | size_t count, loff_t *ppos) | ||
782 | { | ||
783 | wlan_private *priv = file->private_data; | ||
784 | wlan_adapter *adapter = priv->adapter; | ||
785 | struct cmd_ctrl_node *pcmdnode; | ||
786 | struct cmd_ds_command *pcmdptr; | ||
787 | struct cmd_ds_802_11_subscribe_event *event; | ||
788 | void *response_buf; | ||
789 | int res, cmd_len; | ||
790 | ssize_t pos = 0; | ||
791 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
792 | char *buf = (char *)addr; | ||
793 | |||
794 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
795 | if (res < 0) { | ||
796 | free_page(addr); | ||
797 | return res; | ||
798 | } | ||
799 | |||
800 | event = &pcmdptr->params.subscribe_event; | ||
801 | event->action = cmd_act_get; | ||
802 | pcmdptr->size = | ||
803 | cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); | ||
804 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
805 | wake_up_interruptible(&priv->mainthread.waitq); | ||
806 | |||
807 | /* Sleep until response is generated by FW */ | ||
808 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
809 | pcmdnode->cmdwaitqwoken); | ||
810 | |||
811 | pcmdptr = response_buf; | ||
812 | |||
813 | if (pcmdptr->result) { | ||
814 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
815 | pcmdptr->result); | ||
816 | kfree(response_buf); | ||
817 | free_page(addr); | ||
818 | return 0; | ||
819 | } | ||
820 | |||
821 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
822 | lbs_pr_err("command response incorrect!\n"); | ||
823 | kfree(response_buf); | ||
824 | free_page(addr); | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
829 | event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); | ||
830 | while (cmd_len < pcmdptr->size) { | ||
831 | struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); | ||
832 | switch(header->type) { | ||
833 | struct mrvlietypes_failurecount *failcount; | ||
834 | case TLV_TYPE_FAILCOUNT: | ||
835 | failcount = (struct mrvlietypes_failurecount *)(response_buf + cmd_len); | ||
836 | pos += snprintf(buf+pos, len-pos, "%d %d %d\n", | ||
837 | failcount->failvalue, | ||
838 | failcount->Failfreq, | ||
839 | (event->events & 0x0004)?1:0); | ||
840 | default: | ||
841 | cmd_len += sizeof(struct mrvlietypes_failurecount); | ||
842 | break; | ||
843 | } | ||
844 | } | ||
845 | |||
846 | kfree(response_buf); | ||
847 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
848 | free_page(addr); | ||
849 | return res; | ||
850 | } | ||
851 | |||
852 | static ssize_t libertas_failcount_write(struct file *file, | ||
853 | const char __user *userbuf, | ||
854 | size_t count, loff_t *ppos) | ||
855 | { | ||
856 | wlan_private *priv = file->private_data; | ||
857 | wlan_adapter *adapter = priv->adapter; | ||
858 | ssize_t res, buf_size; | ||
859 | int value, freq, subscribed, cmd_len; | ||
860 | struct cmd_ctrl_node *pcmdnode; | ||
861 | struct cmd_ds_command *pcmdptr; | ||
862 | struct cmd_ds_802_11_subscribe_event *event; | ||
863 | struct mrvlietypes_failurecount *failcount; | ||
864 | void *response_buf; | ||
865 | u16 event_bitmap; | ||
866 | u8 *ptr; | ||
867 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
868 | char *buf = (char *)addr; | ||
869 | |||
870 | buf_size = min(count, len - 1); | ||
871 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
872 | res = -EFAULT; | ||
873 | goto out_unlock; | ||
874 | } | ||
875 | res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); | ||
876 | if (res != 3) { | ||
877 | res = -EFAULT; | ||
878 | goto out_unlock; | ||
879 | } | ||
880 | |||
881 | event_bitmap = libertas_get_events_bitmap(priv); | ||
882 | |||
883 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
884 | if (res < 0) | ||
885 | goto out_unlock; | ||
886 | |||
887 | event = &pcmdptr->params.subscribe_event; | ||
888 | event->action = cmd_act_set; | ||
889 | pcmdptr->size = cpu_to_le16(S_DS_GEN + | ||
890 | sizeof(struct cmd_ds_802_11_subscribe_event) + | ||
891 | sizeof(struct mrvlietypes_failurecount)); | ||
892 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
893 | ptr = (u8*) pcmdptr+cmd_len; | ||
894 | failcount = (struct mrvlietypes_failurecount *)(ptr); | ||
895 | failcount->header.type = cpu_to_le16(TLV_TYPE_FAILCOUNT); | ||
896 | failcount->header.len = 2; | ||
897 | failcount->failvalue = cpu_to_le16(value); | ||
898 | failcount->Failfreq = cpu_to_le16(freq); | ||
899 | event_bitmap |= subscribed ? 0x0004 : 0x0; | ||
900 | event->events = event_bitmap; | ||
901 | |||
902 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
903 | wake_up_interruptible(&priv->mainthread.waitq); | ||
904 | |||
905 | /* Sleep until response is generated by FW */ | ||
906 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
907 | pcmdnode->cmdwaitqwoken); | ||
908 | |||
909 | pcmdptr = (struct cmd_ds_command *)response_buf; | ||
910 | |||
911 | if (pcmdptr->result) { | ||
912 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
913 | pcmdptr->result); | ||
914 | kfree(response_buf); | ||
915 | free_page(addr); | ||
916 | return 0; | ||
917 | } | ||
918 | |||
919 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
920 | lbs_pr_err("command response incorrect!\n"); | ||
921 | kfree(response_buf); | ||
922 | free_page(addr); | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | res = count; | ||
927 | out_unlock: | ||
928 | free_page(addr); | ||
929 | return res; | ||
930 | } | ||
931 | |||
932 | static ssize_t libertas_bcnmiss_read(struct file *file, char __user *userbuf, | ||
933 | size_t count, loff_t *ppos) | ||
934 | { | ||
935 | wlan_private *priv = file->private_data; | ||
936 | wlan_adapter *adapter = priv->adapter; | ||
937 | struct cmd_ctrl_node *pcmdnode; | ||
938 | struct cmd_ds_command *pcmdptr; | ||
939 | struct cmd_ds_802_11_subscribe_event *event; | ||
940 | void *response_buf; | ||
941 | int res, cmd_len; | ||
942 | ssize_t pos = 0; | ||
943 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
944 | char *buf = (char *)addr; | ||
945 | |||
946 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
947 | if (res < 0) { | ||
948 | free_page(addr); | ||
949 | return res; | ||
950 | } | ||
951 | |||
952 | event = &pcmdptr->params.subscribe_event; | ||
953 | event->action = cmd_act_get; | ||
954 | pcmdptr->size = | ||
955 | cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); | ||
956 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
957 | wake_up_interruptible(&priv->mainthread.waitq); | ||
958 | |||
959 | /* Sleep until response is generated by FW */ | ||
960 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
961 | pcmdnode->cmdwaitqwoken); | ||
962 | |||
963 | pcmdptr = response_buf; | ||
964 | |||
965 | if (pcmdptr->result) { | ||
966 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
967 | pcmdptr->result); | ||
968 | free_page(addr); | ||
969 | kfree(response_buf); | ||
970 | return 0; | ||
971 | } | ||
972 | |||
973 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
974 | lbs_pr_err("command response incorrect!\n"); | ||
975 | free_page(addr); | ||
976 | kfree(response_buf); | ||
977 | return 0; | ||
978 | } | ||
979 | |||
980 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
981 | event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); | ||
982 | while (cmd_len < pcmdptr->size) { | ||
983 | struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); | ||
984 | switch(header->type) { | ||
985 | struct mrvlietypes_beaconsmissed *bcnmiss; | ||
986 | case TLV_TYPE_BCNMISS: | ||
987 | bcnmiss = (struct mrvlietypes_beaconsmissed *)(response_buf + cmd_len); | ||
988 | pos += snprintf(buf+pos, len-pos, "%d N/A %d\n", | ||
989 | bcnmiss->beaconmissed, | ||
990 | (event->events & 0x0008)?1:0); | ||
991 | default: | ||
992 | cmd_len += sizeof(struct mrvlietypes_beaconsmissed); | ||
993 | break; | ||
994 | } | ||
995 | } | ||
996 | |||
997 | kfree(response_buf); | ||
998 | |||
999 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
1000 | free_page(addr); | ||
1001 | return res; | ||
1002 | } | ||
1003 | |||
1004 | static ssize_t libertas_bcnmiss_write(struct file *file, | ||
1005 | const char __user *userbuf, | ||
1006 | size_t count, loff_t *ppos) | ||
1007 | { | ||
1008 | wlan_private *priv = file->private_data; | ||
1009 | wlan_adapter *adapter = priv->adapter; | ||
1010 | ssize_t res, buf_size; | ||
1011 | int value, freq, subscribed, cmd_len; | ||
1012 | struct cmd_ctrl_node *pcmdnode; | ||
1013 | struct cmd_ds_command *pcmdptr; | ||
1014 | struct cmd_ds_802_11_subscribe_event *event; | ||
1015 | struct mrvlietypes_beaconsmissed *bcnmiss; | ||
1016 | void *response_buf; | ||
1017 | u16 event_bitmap; | ||
1018 | u8 *ptr; | ||
1019 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1020 | char *buf = (char *)addr; | ||
1021 | |||
1022 | buf_size = min(count, len - 1); | ||
1023 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1024 | res = -EFAULT; | ||
1025 | goto out_unlock; | ||
1026 | } | ||
1027 | res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); | ||
1028 | if (res != 3) { | ||
1029 | res = -EFAULT; | ||
1030 | goto out_unlock; | ||
1031 | } | ||
1032 | |||
1033 | event_bitmap = libertas_get_events_bitmap(priv); | ||
1034 | |||
1035 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
1036 | if (res < 0) | ||
1037 | goto out_unlock; | ||
1038 | |||
1039 | event = &pcmdptr->params.subscribe_event; | ||
1040 | event->action = cmd_act_set; | ||
1041 | pcmdptr->size = cpu_to_le16(S_DS_GEN + | ||
1042 | sizeof(struct cmd_ds_802_11_subscribe_event) + | ||
1043 | sizeof(struct mrvlietypes_beaconsmissed)); | ||
1044 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
1045 | ptr = (u8*) pcmdptr+cmd_len; | ||
1046 | bcnmiss = (struct mrvlietypes_beaconsmissed *)(ptr); | ||
1047 | bcnmiss->header.type = cpu_to_le16(TLV_TYPE_BCNMISS); | ||
1048 | bcnmiss->header.len = 2; | ||
1049 | bcnmiss->beaconmissed = cpu_to_le16(value); | ||
1050 | event_bitmap |= subscribed ? 0x0008 : 0x0; | ||
1051 | event->events = event_bitmap; | ||
1052 | |||
1053 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
1054 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1055 | |||
1056 | /* Sleep until response is generated by FW */ | ||
1057 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
1058 | pcmdnode->cmdwaitqwoken); | ||
1059 | |||
1060 | pcmdptr = response_buf; | ||
1061 | |||
1062 | if (pcmdptr->result) { | ||
1063 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
1064 | pcmdptr->result); | ||
1065 | kfree(response_buf); | ||
1066 | free_page(addr); | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
1071 | lbs_pr_err("command response incorrect!\n"); | ||
1072 | free_page(addr); | ||
1073 | kfree(response_buf); | ||
1074 | return 0; | ||
1075 | } | ||
1076 | |||
1077 | res = count; | ||
1078 | out_unlock: | ||
1079 | free_page(addr); | ||
1080 | return res; | ||
1081 | } | ||
1082 | |||
1083 | static ssize_t libertas_highrssi_read(struct file *file, char __user *userbuf, | ||
1084 | size_t count, loff_t *ppos) | ||
1085 | { | ||
1086 | wlan_private *priv = file->private_data; | ||
1087 | wlan_adapter *adapter = priv->adapter; | ||
1088 | struct cmd_ctrl_node *pcmdnode; | ||
1089 | struct cmd_ds_command *pcmdptr; | ||
1090 | struct cmd_ds_802_11_subscribe_event *event; | ||
1091 | void *response_buf; | ||
1092 | int res, cmd_len; | ||
1093 | ssize_t pos = 0; | ||
1094 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1095 | char *buf = (char *)addr; | ||
1096 | |||
1097 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
1098 | if (res < 0) { | ||
1099 | free_page(addr); | ||
1100 | return res; | ||
1101 | } | ||
1102 | |||
1103 | event = &pcmdptr->params.subscribe_event; | ||
1104 | event->action = cmd_act_get; | ||
1105 | pcmdptr->size = | ||
1106 | cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); | ||
1107 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
1108 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1109 | |||
1110 | /* Sleep until response is generated by FW */ | ||
1111 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
1112 | pcmdnode->cmdwaitqwoken); | ||
1113 | |||
1114 | pcmdptr = response_buf; | ||
1115 | |||
1116 | if (pcmdptr->result) { | ||
1117 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
1118 | pcmdptr->result); | ||
1119 | kfree(response_buf); | ||
1120 | free_page(addr); | ||
1121 | return 0; | ||
1122 | } | ||
1123 | |||
1124 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
1125 | lbs_pr_err("command response incorrect!\n"); | ||
1126 | kfree(response_buf); | ||
1127 | free_page(addr); | ||
1128 | return 0; | ||
1129 | } | ||
1130 | |||
1131 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
1132 | event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); | ||
1133 | while (cmd_len < pcmdptr->size) { | ||
1134 | struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); | ||
1135 | switch(header->type) { | ||
1136 | struct mrvlietypes_rssithreshold *Highrssi; | ||
1137 | case TLV_TYPE_RSSI_HIGH: | ||
1138 | Highrssi = (struct mrvlietypes_rssithreshold *)(response_buf + cmd_len); | ||
1139 | pos += snprintf(buf+pos, len-pos, "%d %d %d\n", | ||
1140 | Highrssi->rssivalue, | ||
1141 | Highrssi->rssifreq, | ||
1142 | (event->events & 0x0010)?1:0); | ||
1143 | default: | ||
1144 | cmd_len += sizeof(struct mrvlietypes_snrthreshold); | ||
1145 | break; | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | kfree(response_buf); | ||
1150 | |||
1151 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
1152 | free_page(addr); | ||
1153 | return res; | ||
1154 | } | ||
1155 | |||
1156 | static ssize_t libertas_highrssi_write(struct file *file, | ||
1157 | const char __user *userbuf, | ||
1158 | size_t count, loff_t *ppos) | ||
1159 | { | ||
1160 | wlan_private *priv = file->private_data; | ||
1161 | wlan_adapter *adapter = priv->adapter; | ||
1162 | ssize_t res, buf_size; | ||
1163 | int value, freq, subscribed, cmd_len; | ||
1164 | struct cmd_ctrl_node *pcmdnode; | ||
1165 | struct cmd_ds_command *pcmdptr; | ||
1166 | struct cmd_ds_802_11_subscribe_event *event; | ||
1167 | struct mrvlietypes_rssithreshold *rssi_threshold; | ||
1168 | void *response_buf; | ||
1169 | u16 event_bitmap; | ||
1170 | u8 *ptr; | ||
1171 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1172 | char *buf = (char *)addr; | ||
1173 | |||
1174 | buf_size = min(count, len - 1); | ||
1175 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1176 | res = -EFAULT; | ||
1177 | goto out_unlock; | ||
1178 | } | ||
1179 | res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); | ||
1180 | if (res != 3) { | ||
1181 | res = -EFAULT; | ||
1182 | goto out_unlock; | ||
1183 | } | ||
1184 | |||
1185 | event_bitmap = libertas_get_events_bitmap(priv); | ||
1186 | |||
1187 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
1188 | if (res < 0) | ||
1189 | goto out_unlock; | ||
1190 | |||
1191 | event = &pcmdptr->params.subscribe_event; | ||
1192 | event->action = cmd_act_set; | ||
1193 | pcmdptr->size = cpu_to_le16(S_DS_GEN + | ||
1194 | sizeof(struct cmd_ds_802_11_subscribe_event) + | ||
1195 | sizeof(struct mrvlietypes_rssithreshold)); | ||
1196 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
1197 | ptr = (u8*) pcmdptr+cmd_len; | ||
1198 | rssi_threshold = (struct mrvlietypes_rssithreshold *)(ptr); | ||
1199 | rssi_threshold->header.type = cpu_to_le16(TLV_TYPE_RSSI_HIGH); | ||
1200 | rssi_threshold->header.len = 2; | ||
1201 | rssi_threshold->rssivalue = cpu_to_le16(value); | ||
1202 | rssi_threshold->rssifreq = cpu_to_le16(freq); | ||
1203 | event_bitmap |= subscribed ? 0x0010 : 0x0; | ||
1204 | event->events = event_bitmap; | ||
1205 | |||
1206 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
1207 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1208 | |||
1209 | /* Sleep until response is generated by FW */ | ||
1210 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
1211 | pcmdnode->cmdwaitqwoken); | ||
1212 | |||
1213 | pcmdptr = response_buf; | ||
1214 | |||
1215 | if (pcmdptr->result) { | ||
1216 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
1217 | pcmdptr->result); | ||
1218 | kfree(response_buf); | ||
1219 | return 0; | ||
1220 | } | ||
1221 | |||
1222 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
1223 | lbs_pr_err("command response incorrect!\n"); | ||
1224 | kfree(response_buf); | ||
1225 | return 0; | ||
1226 | } | ||
1227 | |||
1228 | res = count; | ||
1229 | out_unlock: | ||
1230 | free_page(addr); | ||
1231 | return res; | ||
1232 | } | ||
1233 | |||
1234 | static ssize_t libertas_highsnr_read(struct file *file, char __user *userbuf, | ||
1235 | size_t count, loff_t *ppos) | ||
1236 | { | ||
1237 | wlan_private *priv = file->private_data; | ||
1238 | wlan_adapter *adapter = priv->adapter; | ||
1239 | struct cmd_ctrl_node *pcmdnode; | ||
1240 | struct cmd_ds_command *pcmdptr; | ||
1241 | struct cmd_ds_802_11_subscribe_event *event; | ||
1242 | void *response_buf; | ||
1243 | int res, cmd_len; | ||
1244 | ssize_t pos = 0; | ||
1245 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1246 | char *buf = (char *)addr; | ||
1247 | |||
1248 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
1249 | if (res < 0) { | ||
1250 | free_page(addr); | ||
1251 | return res; | ||
1252 | } | ||
1253 | |||
1254 | event = &pcmdptr->params.subscribe_event; | ||
1255 | event->action = cmd_act_get; | ||
1256 | pcmdptr->size = | ||
1257 | cpu_to_le16(sizeof(struct cmd_ds_802_11_subscribe_event) + S_DS_GEN); | ||
1258 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
1259 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1260 | |||
1261 | /* Sleep until response is generated by FW */ | ||
1262 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
1263 | pcmdnode->cmdwaitqwoken); | ||
1264 | |||
1265 | pcmdptr = response_buf; | ||
1266 | |||
1267 | if (pcmdptr->result) { | ||
1268 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
1269 | pcmdptr->result); | ||
1270 | kfree(response_buf); | ||
1271 | free_page(addr); | ||
1272 | return 0; | ||
1273 | } | ||
1274 | |||
1275 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
1276 | lbs_pr_err("command response incorrect!\n"); | ||
1277 | kfree(response_buf); | ||
1278 | free_page(addr); | ||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1282 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
1283 | event = (struct cmd_ds_802_11_subscribe_event *)(response_buf + S_DS_GEN); | ||
1284 | while (cmd_len < pcmdptr->size) { | ||
1285 | struct mrvlietypesheader *header = (struct mrvlietypesheader *)(response_buf + cmd_len); | ||
1286 | switch(header->type) { | ||
1287 | struct mrvlietypes_snrthreshold *HighSnr; | ||
1288 | case TLV_TYPE_SNR_HIGH: | ||
1289 | HighSnr = (struct mrvlietypes_snrthreshold *)(response_buf + cmd_len); | ||
1290 | pos += snprintf(buf+pos, len-pos, "%d %d %d\n", | ||
1291 | HighSnr->snrvalue, | ||
1292 | HighSnr->snrfreq, | ||
1293 | (event->events & 0x0020)?1:0); | ||
1294 | default: | ||
1295 | cmd_len += sizeof(struct mrvlietypes_snrthreshold); | ||
1296 | break; | ||
1297 | } | ||
1298 | } | ||
1299 | |||
1300 | kfree(response_buf); | ||
1301 | |||
1302 | res = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
1303 | free_page(addr); | ||
1304 | return res; | ||
1305 | } | ||
1306 | |||
1307 | static ssize_t libertas_highsnr_write(struct file *file, | ||
1308 | const char __user *userbuf, | ||
1309 | size_t count, loff_t *ppos) | ||
1310 | { | ||
1311 | wlan_private *priv = file->private_data; | ||
1312 | wlan_adapter *adapter = priv->adapter; | ||
1313 | ssize_t res, buf_size; | ||
1314 | int value, freq, subscribed, cmd_len; | ||
1315 | struct cmd_ctrl_node *pcmdnode; | ||
1316 | struct cmd_ds_command *pcmdptr; | ||
1317 | struct cmd_ds_802_11_subscribe_event *event; | ||
1318 | struct mrvlietypes_snrthreshold *snr_threshold; | ||
1319 | void *response_buf; | ||
1320 | u16 event_bitmap; | ||
1321 | u8 *ptr; | ||
1322 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1323 | char *buf = (char *)addr; | ||
1324 | |||
1325 | buf_size = min(count, len - 1); | ||
1326 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1327 | res = -EFAULT; | ||
1328 | goto out_unlock; | ||
1329 | } | ||
1330 | res = sscanf(buf, "%d %d %d", &value, &freq, &subscribed); | ||
1331 | if (res != 3) { | ||
1332 | res = -EFAULT; | ||
1333 | goto out_unlock; | ||
1334 | } | ||
1335 | |||
1336 | event_bitmap = libertas_get_events_bitmap(priv); | ||
1337 | |||
1338 | res = libertas_event_initcmd(priv, &response_buf, &pcmdnode, &pcmdptr); | ||
1339 | if (res < 0) | ||
1340 | goto out_unlock; | ||
1341 | |||
1342 | event = &pcmdptr->params.subscribe_event; | ||
1343 | event->action = cmd_act_set; | ||
1344 | pcmdptr->size = cpu_to_le16(S_DS_GEN + | ||
1345 | sizeof(struct cmd_ds_802_11_subscribe_event) + | ||
1346 | sizeof(struct mrvlietypes_snrthreshold)); | ||
1347 | cmd_len = S_DS_GEN + sizeof(struct cmd_ds_802_11_subscribe_event); | ||
1348 | ptr = (u8*) pcmdptr+cmd_len; | ||
1349 | snr_threshold = (struct mrvlietypes_snrthreshold *)(ptr); | ||
1350 | snr_threshold->header.type = cpu_to_le16(TLV_TYPE_SNR_HIGH); | ||
1351 | snr_threshold->header.len = 2; | ||
1352 | snr_threshold->snrvalue = cpu_to_le16(value); | ||
1353 | snr_threshold->snrfreq = cpu_to_le16(freq); | ||
1354 | event_bitmap |= subscribed ? 0x0020 : 0x0; | ||
1355 | event->events = event_bitmap; | ||
1356 | |||
1357 | libertas_queue_cmd(adapter, pcmdnode, 1); | ||
1358 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1359 | |||
1360 | /* Sleep until response is generated by FW */ | ||
1361 | wait_event_interruptible(pcmdnode->cmdwait_q, | ||
1362 | pcmdnode->cmdwaitqwoken); | ||
1363 | |||
1364 | pcmdptr = response_buf; | ||
1365 | |||
1366 | if (pcmdptr->result) { | ||
1367 | lbs_pr_err("%s: fail, result=%d\n", __FUNCTION__, | ||
1368 | pcmdptr->result); | ||
1369 | kfree(response_buf); | ||
1370 | free_page(addr); | ||
1371 | return 0; | ||
1372 | } | ||
1373 | |||
1374 | if (pcmdptr->command != cmd_ret_802_11_subscribe_event) { | ||
1375 | lbs_pr_err("command response incorrect!\n"); | ||
1376 | kfree(response_buf); | ||
1377 | free_page(addr); | ||
1378 | return 0; | ||
1379 | } | ||
1380 | |||
1381 | res = count; | ||
1382 | out_unlock: | ||
1383 | free_page(addr); | ||
1384 | return res; | ||
1385 | } | ||
1386 | |||
1387 | static ssize_t libertas_rdmac_read(struct file *file, char __user *userbuf, | ||
1388 | size_t count, loff_t *ppos) | ||
1389 | { | ||
1390 | wlan_private *priv = file->private_data; | ||
1391 | wlan_adapter *adapter = priv->adapter; | ||
1392 | struct wlan_offset_value offval; | ||
1393 | ssize_t pos = 0; | ||
1394 | int ret; | ||
1395 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1396 | char *buf = (char *)addr; | ||
1397 | |||
1398 | offval.offset = priv->mac_offset; | ||
1399 | offval.value = 0; | ||
1400 | |||
1401 | ret = libertas_prepare_and_send_command(priv, | ||
1402 | cmd_mac_reg_access, 0, | ||
1403 | cmd_option_waitforrsp, 0, &offval); | ||
1404 | mdelay(10); | ||
1405 | pos += snprintf(buf+pos, len-pos, "MAC[0x%x] = 0x%08x\n", | ||
1406 | priv->mac_offset, adapter->offsetvalue.value); | ||
1407 | |||
1408 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
1409 | free_page(addr); | ||
1410 | return ret; | ||
1411 | } | ||
1412 | |||
1413 | static ssize_t libertas_rdmac_write(struct file *file, | ||
1414 | const char __user *userbuf, | ||
1415 | size_t count, loff_t *ppos) | ||
1416 | { | ||
1417 | wlan_private *priv = file->private_data; | ||
1418 | ssize_t res, buf_size; | ||
1419 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1420 | char *buf = (char *)addr; | ||
1421 | |||
1422 | buf_size = min(count, len - 1); | ||
1423 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1424 | res = -EFAULT; | ||
1425 | goto out_unlock; | ||
1426 | } | ||
1427 | priv->mac_offset = simple_strtoul((char *)buf, NULL, 16); | ||
1428 | res = count; | ||
1429 | out_unlock: | ||
1430 | free_page(addr); | ||
1431 | return res; | ||
1432 | } | ||
1433 | |||
1434 | static ssize_t libertas_wrmac_write(struct file *file, | ||
1435 | const char __user *userbuf, | ||
1436 | size_t count, loff_t *ppos) | ||
1437 | { | ||
1438 | |||
1439 | wlan_private *priv = file->private_data; | ||
1440 | ssize_t res, buf_size; | ||
1441 | u32 offset, value; | ||
1442 | struct wlan_offset_value offval; | ||
1443 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1444 | char *buf = (char *)addr; | ||
1445 | |||
1446 | buf_size = min(count, len - 1); | ||
1447 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1448 | res = -EFAULT; | ||
1449 | goto out_unlock; | ||
1450 | } | ||
1451 | res = sscanf(buf, "%x %x", &offset, &value); | ||
1452 | if (res != 2) { | ||
1453 | res = -EFAULT; | ||
1454 | goto out_unlock; | ||
1455 | } | ||
1456 | |||
1457 | offval.offset = offset; | ||
1458 | offval.value = value; | ||
1459 | res = libertas_prepare_and_send_command(priv, | ||
1460 | cmd_mac_reg_access, 1, | ||
1461 | cmd_option_waitforrsp, 0, &offval); | ||
1462 | mdelay(10); | ||
1463 | |||
1464 | res = count; | ||
1465 | out_unlock: | ||
1466 | free_page(addr); | ||
1467 | return res; | ||
1468 | } | ||
1469 | |||
1470 | static ssize_t libertas_rdbbp_read(struct file *file, char __user *userbuf, | ||
1471 | size_t count, loff_t *ppos) | ||
1472 | { | ||
1473 | wlan_private *priv = file->private_data; | ||
1474 | wlan_adapter *adapter = priv->adapter; | ||
1475 | struct wlan_offset_value offval; | ||
1476 | ssize_t pos = 0; | ||
1477 | int ret; | ||
1478 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1479 | char *buf = (char *)addr; | ||
1480 | |||
1481 | offval.offset = priv->bbp_offset; | ||
1482 | offval.value = 0; | ||
1483 | |||
1484 | ret = libertas_prepare_and_send_command(priv, | ||
1485 | cmd_bbp_reg_access, 0, | ||
1486 | cmd_option_waitforrsp, 0, &offval); | ||
1487 | mdelay(10); | ||
1488 | pos += snprintf(buf+pos, len-pos, "BBP[0x%x] = 0x%08x\n", | ||
1489 | priv->bbp_offset, adapter->offsetvalue.value); | ||
1490 | |||
1491 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
1492 | free_page(addr); | ||
1493 | |||
1494 | return ret; | ||
1495 | } | ||
1496 | |||
1497 | static ssize_t libertas_rdbbp_write(struct file *file, | ||
1498 | const char __user *userbuf, | ||
1499 | size_t count, loff_t *ppos) | ||
1500 | { | ||
1501 | wlan_private *priv = file->private_data; | ||
1502 | ssize_t res, buf_size; | ||
1503 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1504 | char *buf = (char *)addr; | ||
1505 | |||
1506 | buf_size = min(count, len - 1); | ||
1507 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1508 | res = -EFAULT; | ||
1509 | goto out_unlock; | ||
1510 | } | ||
1511 | priv->bbp_offset = simple_strtoul((char *)buf, NULL, 16); | ||
1512 | res = count; | ||
1513 | out_unlock: | ||
1514 | free_page(addr); | ||
1515 | return res; | ||
1516 | } | ||
1517 | |||
1518 | static ssize_t libertas_wrbbp_write(struct file *file, | ||
1519 | const char __user *userbuf, | ||
1520 | size_t count, loff_t *ppos) | ||
1521 | { | ||
1522 | |||
1523 | wlan_private *priv = file->private_data; | ||
1524 | ssize_t res, buf_size; | ||
1525 | u32 offset, value; | ||
1526 | struct wlan_offset_value offval; | ||
1527 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1528 | char *buf = (char *)addr; | ||
1529 | |||
1530 | buf_size = min(count, len - 1); | ||
1531 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1532 | res = -EFAULT; | ||
1533 | goto out_unlock; | ||
1534 | } | ||
1535 | res = sscanf(buf, "%x %x", &offset, &value); | ||
1536 | if (res != 2) { | ||
1537 | res = -EFAULT; | ||
1538 | goto out_unlock; | ||
1539 | } | ||
1540 | |||
1541 | offval.offset = offset; | ||
1542 | offval.value = value; | ||
1543 | res = libertas_prepare_and_send_command(priv, | ||
1544 | cmd_bbp_reg_access, 1, | ||
1545 | cmd_option_waitforrsp, 0, &offval); | ||
1546 | mdelay(10); | ||
1547 | |||
1548 | res = count; | ||
1549 | out_unlock: | ||
1550 | free_page(addr); | ||
1551 | return res; | ||
1552 | } | ||
1553 | |||
1554 | static ssize_t libertas_rdrf_read(struct file *file, char __user *userbuf, | ||
1555 | size_t count, loff_t *ppos) | ||
1556 | { | ||
1557 | wlan_private *priv = file->private_data; | ||
1558 | wlan_adapter *adapter = priv->adapter; | ||
1559 | struct wlan_offset_value offval; | ||
1560 | ssize_t pos = 0; | ||
1561 | int ret; | ||
1562 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1563 | char *buf = (char *)addr; | ||
1564 | |||
1565 | offval.offset = priv->rf_offset; | ||
1566 | offval.value = 0; | ||
1567 | |||
1568 | ret = libertas_prepare_and_send_command(priv, | ||
1569 | cmd_rf_reg_access, 0, | ||
1570 | cmd_option_waitforrsp, 0, &offval); | ||
1571 | mdelay(10); | ||
1572 | pos += snprintf(buf+pos, len-pos, "RF[0x%x] = 0x%08x\n", | ||
1573 | priv->rf_offset, adapter->offsetvalue.value); | ||
1574 | |||
1575 | ret = simple_read_from_buffer(userbuf, count, ppos, buf, pos); | ||
1576 | free_page(addr); | ||
1577 | |||
1578 | return ret; | ||
1579 | } | ||
1580 | |||
1581 | static ssize_t libertas_rdrf_write(struct file *file, | ||
1582 | const char __user *userbuf, | ||
1583 | size_t count, loff_t *ppos) | ||
1584 | { | ||
1585 | wlan_private *priv = file->private_data; | ||
1586 | ssize_t res, buf_size; | ||
1587 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1588 | char *buf = (char *)addr; | ||
1589 | |||
1590 | buf_size = min(count, len - 1); | ||
1591 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1592 | res = -EFAULT; | ||
1593 | goto out_unlock; | ||
1594 | } | ||
1595 | priv->rf_offset = simple_strtoul((char *)buf, NULL, 16); | ||
1596 | res = count; | ||
1597 | out_unlock: | ||
1598 | free_page(addr); | ||
1599 | return res; | ||
1600 | } | ||
1601 | |||
1602 | static ssize_t libertas_wrrf_write(struct file *file, | ||
1603 | const char __user *userbuf, | ||
1604 | size_t count, loff_t *ppos) | ||
1605 | { | ||
1606 | |||
1607 | wlan_private *priv = file->private_data; | ||
1608 | ssize_t res, buf_size; | ||
1609 | u32 offset, value; | ||
1610 | struct wlan_offset_value offval; | ||
1611 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1612 | char *buf = (char *)addr; | ||
1613 | |||
1614 | buf_size = min(count, len - 1); | ||
1615 | if (copy_from_user(buf, userbuf, buf_size)) { | ||
1616 | res = -EFAULT; | ||
1617 | goto out_unlock; | ||
1618 | } | ||
1619 | res = sscanf(buf, "%x %x", &offset, &value); | ||
1620 | if (res != 2) { | ||
1621 | res = -EFAULT; | ||
1622 | goto out_unlock; | ||
1623 | } | ||
1624 | |||
1625 | offval.offset = offset; | ||
1626 | offval.value = value; | ||
1627 | res = libertas_prepare_and_send_command(priv, | ||
1628 | cmd_rf_reg_access, 1, | ||
1629 | cmd_option_waitforrsp, 0, &offval); | ||
1630 | mdelay(10); | ||
1631 | |||
1632 | res = count; | ||
1633 | out_unlock: | ||
1634 | free_page(addr); | ||
1635 | return res; | ||
1636 | } | ||
1637 | |||
1638 | #define FOPS(fread, fwrite) { \ | ||
1639 | .owner = THIS_MODULE, \ | ||
1640 | .open = open_file_generic, \ | ||
1641 | .read = (fread), \ | ||
1642 | .write = (fwrite), \ | ||
1643 | } | ||
1644 | |||
1645 | struct libertas_debugfs_files { | ||
1646 | char *name; | ||
1647 | int perm; | ||
1648 | struct file_operations fops; | ||
1649 | }; | ||
1650 | |||
1651 | struct libertas_debugfs_files debugfs_files[] = { | ||
1652 | { "info", 0444, FOPS(libertas_dev_info, write_file_dummy), }, | ||
1653 | { "getscantable", 0444, FOPS(libertas_getscantable, | ||
1654 | write_file_dummy), }, | ||
1655 | { "sleepparams", 0644, FOPS(libertas_sleepparams_read, | ||
1656 | libertas_sleepparams_write), }, | ||
1657 | { "extscan", 0600, FOPS(NULL, libertas_extscan), }, | ||
1658 | { "setuserscan", 0600, FOPS(NULL, libertas_setuserscan), }, | ||
1659 | }; | ||
1660 | |||
1661 | struct libertas_debugfs_files debugfs_events_files[] = { | ||
1662 | {"low_rssi", 0644, FOPS(libertas_lowrssi_read, | ||
1663 | libertas_lowrssi_write), }, | ||
1664 | {"low_snr", 0644, FOPS(libertas_lowsnr_read, | ||
1665 | libertas_lowsnr_write), }, | ||
1666 | {"failure_count", 0644, FOPS(libertas_failcount_read, | ||
1667 | libertas_failcount_write), }, | ||
1668 | {"beacon_missed", 0644, FOPS(libertas_bcnmiss_read, | ||
1669 | libertas_bcnmiss_write), }, | ||
1670 | {"high_rssi", 0644, FOPS(libertas_highrssi_read, | ||
1671 | libertas_highrssi_write), }, | ||
1672 | {"high_snr", 0644, FOPS(libertas_highsnr_read, | ||
1673 | libertas_highsnr_write), }, | ||
1674 | }; | ||
1675 | |||
1676 | struct libertas_debugfs_files debugfs_regs_files[] = { | ||
1677 | {"rdmac", 0644, FOPS(libertas_rdmac_read, libertas_rdmac_write), }, | ||
1678 | {"wrmac", 0600, FOPS(NULL, libertas_wrmac_write), }, | ||
1679 | {"rdbbp", 0644, FOPS(libertas_rdbbp_read, libertas_rdbbp_write), }, | ||
1680 | {"wrbbp", 0600, FOPS(NULL, libertas_wrbbp_write), }, | ||
1681 | {"rdrf", 0644, FOPS(libertas_rdrf_read, libertas_rdrf_write), }, | ||
1682 | {"wrrf", 0600, FOPS(NULL, libertas_wrrf_write), }, | ||
1683 | }; | ||
1684 | |||
1685 | void libertas_debugfs_init(void) | ||
1686 | { | ||
1687 | if (!libertas_dir) | ||
1688 | libertas_dir = debugfs_create_dir("libertas_wireless", NULL); | ||
1689 | |||
1690 | return; | ||
1691 | } | ||
1692 | |||
1693 | void libertas_debugfs_remove(void) | ||
1694 | { | ||
1695 | if (libertas_dir) | ||
1696 | debugfs_remove(libertas_dir); | ||
1697 | return; | ||
1698 | } | ||
1699 | |||
1700 | void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev) | ||
1701 | { | ||
1702 | int i; | ||
1703 | struct libertas_debugfs_files *files; | ||
1704 | if (!libertas_dir) | ||
1705 | goto exit; | ||
1706 | |||
1707 | priv->debugfs_dir = debugfs_create_dir(dev->name, libertas_dir); | ||
1708 | if (!priv->debugfs_dir) | ||
1709 | goto exit; | ||
1710 | |||
1711 | for (i=0; i<ARRAY_SIZE(debugfs_files); i++) { | ||
1712 | files = &debugfs_files[i]; | ||
1713 | priv->debugfs_files[i] = debugfs_create_file(files->name, | ||
1714 | files->perm, | ||
1715 | priv->debugfs_dir, | ||
1716 | priv, | ||
1717 | &files->fops); | ||
1718 | } | ||
1719 | |||
1720 | priv->events_dir = debugfs_create_dir("subscribed_events", priv->debugfs_dir); | ||
1721 | if (!priv->events_dir) | ||
1722 | goto exit; | ||
1723 | |||
1724 | for (i=0; i<ARRAY_SIZE(debugfs_events_files); i++) { | ||
1725 | files = &debugfs_events_files[i]; | ||
1726 | priv->debugfs_events_files[i] = debugfs_create_file(files->name, | ||
1727 | files->perm, | ||
1728 | priv->events_dir, | ||
1729 | priv, | ||
1730 | &files->fops); | ||
1731 | } | ||
1732 | |||
1733 | priv->regs_dir = debugfs_create_dir("registers", priv->debugfs_dir); | ||
1734 | if (!priv->regs_dir) | ||
1735 | goto exit; | ||
1736 | |||
1737 | for (i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) { | ||
1738 | files = &debugfs_regs_files[i]; | ||
1739 | priv->debugfs_regs_files[i] = debugfs_create_file(files->name, | ||
1740 | files->perm, | ||
1741 | priv->regs_dir, | ||
1742 | priv, | ||
1743 | &files->fops); | ||
1744 | } | ||
1745 | |||
1746 | #ifdef PROC_DEBUG | ||
1747 | libertas_debug_init(priv, dev); | ||
1748 | #endif | ||
1749 | exit: | ||
1750 | return; | ||
1751 | } | ||
1752 | |||
1753 | void libertas_debugfs_remove_one(wlan_private *priv) | ||
1754 | { | ||
1755 | int i; | ||
1756 | |||
1757 | for(i=0; i<ARRAY_SIZE(debugfs_regs_files); i++) | ||
1758 | debugfs_remove(priv->debugfs_regs_files[i]); | ||
1759 | |||
1760 | debugfs_remove(priv->regs_dir); | ||
1761 | |||
1762 | for(i=0; i<ARRAY_SIZE(debugfs_files); i++) | ||
1763 | debugfs_remove(priv->debugfs_events_files[i]); | ||
1764 | |||
1765 | debugfs_remove(priv->events_dir); | ||
1766 | #ifdef PROC_DEBUG | ||
1767 | debugfs_remove(priv->debugfs_debug); | ||
1768 | #endif | ||
1769 | for(i=0; i<ARRAY_SIZE(debugfs_files); i++) | ||
1770 | debugfs_remove(priv->debugfs_files[i]); | ||
1771 | } | ||
1772 | |||
1773 | /* debug entry */ | ||
1774 | |||
1775 | #define item_size(n) (FIELD_SIZEOF(wlan_adapter, n)) | ||
1776 | #define item_addr(n) (offsetof(wlan_adapter, n)) | ||
1777 | |||
1778 | struct debug_data { | ||
1779 | char name[32]; | ||
1780 | u32 size; | ||
1781 | u32 addr; | ||
1782 | }; | ||
1783 | |||
1784 | /* To debug any member of wlan_adapter, simply add one line here. | ||
1785 | */ | ||
1786 | static struct debug_data items[] = { | ||
1787 | {"intcounter", item_size(intcounter), item_addr(intcounter)}, | ||
1788 | {"psmode", item_size(psmode), item_addr(psmode)}, | ||
1789 | {"psstate", item_size(psstate), item_addr(psstate)}, | ||
1790 | }; | ||
1791 | |||
1792 | static int num_of_items = ARRAY_SIZE(items); | ||
1793 | |||
1794 | /** | ||
1795 | * @brief proc read function | ||
1796 | * | ||
1797 | * @param page pointer to buffer | ||
1798 | * @param s read data starting position | ||
1799 | * @param off offset | ||
1800 | * @param cnt counter | ||
1801 | * @param eof end of file flag | ||
1802 | * @param data data to output | ||
1803 | * @return number of output data | ||
1804 | */ | ||
1805 | static ssize_t wlan_debugfs_read(struct file *file, char __user *userbuf, | ||
1806 | size_t count, loff_t *ppos) | ||
1807 | { | ||
1808 | int val = 0; | ||
1809 | size_t pos = 0; | ||
1810 | ssize_t res; | ||
1811 | char *p; | ||
1812 | int i; | ||
1813 | struct debug_data *d; | ||
1814 | unsigned long addr = get_zeroed_page(GFP_KERNEL); | ||
1815 | char *buf = (char *)addr; | ||
1816 | |||
1817 | p = buf; | ||
1818 | |||
1819 | d = (struct debug_data *)file->private_data; | ||
1820 | |||
1821 | for (i = 0; i < num_of_items; i++) { | ||
1822 | if (d[i].size == 1) | ||
1823 | val = *((u8 *) d[i].addr); | ||
1824 | else if (d[i].size == 2) | ||
1825 | val = *((u16 *) d[i].addr); | ||
1826 | else if (d[i].size == 4) | ||
1827 | val = *((u32 *) d[i].addr); | ||
1828 | |||
1829 | pos += sprintf(p + pos, "%s=%d\n", d[i].name, val); | ||
1830 | } | ||
1831 | |||
1832 | res = simple_read_from_buffer(userbuf, count, ppos, p, pos); | ||
1833 | |||
1834 | free_page(addr); | ||
1835 | return res; | ||
1836 | } | ||
1837 | |||
1838 | /** | ||
1839 | * @brief proc write function | ||
1840 | * | ||
1841 | * @param f file pointer | ||
1842 | * @param buf pointer to data buffer | ||
1843 | * @param cnt data number to write | ||
1844 | * @param data data to write | ||
1845 | * @return number of data | ||
1846 | */ | ||
1847 | static int wlan_debugfs_write(struct file *f, const char __user *buf, | ||
1848 | size_t cnt, loff_t *ppos) | ||
1849 | { | ||
1850 | int r, i; | ||
1851 | char *pdata; | ||
1852 | char *p; | ||
1853 | char *p0; | ||
1854 | char *p1; | ||
1855 | char *p2; | ||
1856 | struct debug_data *d = (struct debug_data *)f->private_data; | ||
1857 | |||
1858 | pdata = (char *)kmalloc(cnt, GFP_KERNEL); | ||
1859 | if (pdata == NULL) | ||
1860 | return 0; | ||
1861 | |||
1862 | if (copy_from_user(pdata, buf, cnt)) { | ||
1863 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
1864 | kfree(pdata); | ||
1865 | return 0; | ||
1866 | } | ||
1867 | |||
1868 | p0 = pdata; | ||
1869 | for (i = 0; i < num_of_items; i++) { | ||
1870 | do { | ||
1871 | p = strstr(p0, d[i].name); | ||
1872 | if (p == NULL) | ||
1873 | break; | ||
1874 | p1 = strchr(p, '\n'); | ||
1875 | if (p1 == NULL) | ||
1876 | break; | ||
1877 | p0 = p1++; | ||
1878 | p2 = strchr(p, '='); | ||
1879 | if (!p2) | ||
1880 | break; | ||
1881 | p2++; | ||
1882 | r = simple_strtoul(p2, NULL, 0); | ||
1883 | if (d[i].size == 1) | ||
1884 | *((u8 *) d[i].addr) = (u8) r; | ||
1885 | else if (d[i].size == 2) | ||
1886 | *((u16 *) d[i].addr) = (u16) r; | ||
1887 | else if (d[i].size == 4) | ||
1888 | *((u32 *) d[i].addr) = (u32) r; | ||
1889 | break; | ||
1890 | } while (1); | ||
1891 | } | ||
1892 | kfree(pdata); | ||
1893 | |||
1894 | return cnt; | ||
1895 | } | ||
1896 | |||
1897 | static struct file_operations libertas_debug_fops = { | ||
1898 | .owner = THIS_MODULE, | ||
1899 | .open = open_file_generic, | ||
1900 | .write = wlan_debugfs_write, | ||
1901 | .read = wlan_debugfs_read, | ||
1902 | }; | ||
1903 | |||
1904 | /** | ||
1905 | * @brief create debug proc file | ||
1906 | * | ||
1907 | * @param priv pointer wlan_private | ||
1908 | * @param dev pointer net_device | ||
1909 | * @return N/A | ||
1910 | */ | ||
1911 | void libertas_debug_init(wlan_private * priv, struct net_device *dev) | ||
1912 | { | ||
1913 | int i; | ||
1914 | |||
1915 | if (!priv->debugfs_dir) | ||
1916 | return; | ||
1917 | |||
1918 | for (i = 0; i < num_of_items; i++) | ||
1919 | items[i].addr += (u32) priv->adapter; | ||
1920 | |||
1921 | priv->debugfs_debug = debugfs_create_file("debug", 0644, | ||
1922 | priv->debugfs_dir, &items[0], | ||
1923 | &libertas_debug_fops); | ||
1924 | } | ||
1925 | |||
1926 | /** | ||
1927 | * @brief remove proc file | ||
1928 | * | ||
1929 | * @param priv pointer wlan_private | ||
1930 | * @return N/A | ||
1931 | */ | ||
1932 | void libertas_debug_remove(wlan_private * priv) | ||
1933 | { | ||
1934 | debugfs_remove(priv->debugfs_debug); | ||
1935 | } | ||
diff --git a/drivers/net/wireless/libertas/debugfs.h b/drivers/net/wireless/libertas/debugfs.h new file mode 100644 index 000000000000..880a11b95d26 --- /dev/null +++ b/drivers/net/wireless/libertas/debugfs.h | |||
@@ -0,0 +1,6 @@ | |||
1 | void libertas_debugfs_init(void); | ||
2 | void libertas_debugfs_remove(void); | ||
3 | |||
4 | void libertas_debugfs_init_one(wlan_private *priv, struct net_device *dev); | ||
5 | void libertas_debugfs_remove_one(wlan_private *priv); | ||
6 | |||
diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h new file mode 100644 index 000000000000..606bdd002be7 --- /dev/null +++ b/drivers/net/wireless/libertas/decl.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /** | ||
2 | * This file contains declaration referring to | ||
3 | * functions defined in other source files | ||
4 | */ | ||
5 | |||
6 | #ifndef _WLAN_DECL_H_ | ||
7 | #define _WLAN_DECL_H_ | ||
8 | |||
9 | #include "defs.h" | ||
10 | |||
11 | /** Function Prototype Declaration */ | ||
12 | struct wlan_private; | ||
13 | struct sk_buff; | ||
14 | struct net_device; | ||
15 | |||
16 | extern char *libertas_fw_name; | ||
17 | |||
18 | void libertas_free_adapter(wlan_private * priv); | ||
19 | int libertas_set_mac_packet_filter(wlan_private * priv); | ||
20 | |||
21 | int libertas_send_null_packet(wlan_private * priv, u8 pwr_mgmt); | ||
22 | void libertas_send_tx_feedback(wlan_private * priv); | ||
23 | u8 libertas_check_last_packet_indication(wlan_private * priv); | ||
24 | |||
25 | int libertas_free_cmd_buffer(wlan_private * priv); | ||
26 | struct cmd_ctrl_node; | ||
27 | struct cmd_ctrl_node *libertas_get_free_cmd_ctrl_node(wlan_private * priv); | ||
28 | |||
29 | void libertas_set_cmd_ctrl_node(wlan_private * priv, | ||
30 | struct cmd_ctrl_node *ptempnode, | ||
31 | u32 cmd_oid, u16 wait_option, void *pdata_buf); | ||
32 | |||
33 | int libertas_prepare_and_send_command(wlan_private * priv, | ||
34 | u16 cmd_no, | ||
35 | u16 cmd_action, | ||
36 | u16 wait_option, u32 cmd_oid, void *pdata_buf); | ||
37 | |||
38 | void libertas_queue_cmd(wlan_adapter * adapter, struct cmd_ctrl_node *cmdnode, u8 addtail); | ||
39 | |||
40 | int libertas_allocate_cmd_buffer(wlan_private * priv); | ||
41 | int libertas_execute_next_command(wlan_private * priv); | ||
42 | int libertas_process_event(wlan_private * priv); | ||
43 | void libertas_interrupt(struct net_device *); | ||
44 | int libertas_set_radio_control(wlan_private * priv); | ||
45 | u32 libertas_index_to_data_rate(u8 index); | ||
46 | u8 libertas_data_rate_to_index(u32 rate); | ||
47 | void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen); | ||
48 | |||
49 | int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb); | ||
50 | |||
51 | /** The proc fs interface */ | ||
52 | int libertas_process_rx_command(wlan_private * priv); | ||
53 | int libertas_process_tx(wlan_private * priv, struct sk_buff *skb); | ||
54 | void libertas_cleanup_and_insert_cmd(wlan_private * priv, | ||
55 | struct cmd_ctrl_node *ptempcmd); | ||
56 | void __libertas_cleanup_and_insert_cmd(wlan_private * priv, | ||
57 | struct cmd_ctrl_node *ptempcmd); | ||
58 | |||
59 | int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band); | ||
60 | |||
61 | int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *); | ||
62 | |||
63 | void libertas_ps_sleep(wlan_private * priv, int wait_option); | ||
64 | void libertas_ps_confirm_sleep(wlan_private * priv, u16 psmode); | ||
65 | void libertas_ps_wakeup(wlan_private * priv, int wait_option); | ||
66 | |||
67 | void libertas_tx_runqueue(wlan_private *priv); | ||
68 | |||
69 | extern struct chan_freq_power *libertas_find_cfp_by_band_and_channel( | ||
70 | wlan_adapter * adapter, u8 band, u16 channel); | ||
71 | |||
72 | extern void libertas_mac_event_disconnected(wlan_private * priv); | ||
73 | |||
74 | void libertas_send_iwevcustom_event(wlan_private * priv, s8 * str); | ||
75 | |||
76 | int reset_device(wlan_private *priv); | ||
77 | /* main.c */ | ||
78 | extern struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, | ||
79 | int *cfp_no); | ||
80 | wlan_private *wlan_add_card(void *card); | ||
81 | int wlan_remove_card(void *card); | ||
82 | |||
83 | #endif /* _WLAN_DECL_H_ */ | ||
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h new file mode 100644 index 000000000000..fb1478c1b87d --- /dev/null +++ b/drivers/net/wireless/libertas/defs.h | |||
@@ -0,0 +1,369 @@ | |||
1 | /** | ||
2 | * This header file contains global constant/enum definitions, | ||
3 | * global variable declaration. | ||
4 | */ | ||
5 | #ifndef _WLAN_DEFS_H_ | ||
6 | #define _WLAN_DEFS_H_ | ||
7 | |||
8 | #include <linux/spinlock.h> | ||
9 | |||
10 | extern unsigned int libertas_debug; | ||
11 | |||
12 | #define DRV_NAME "usb8xxx" | ||
13 | |||
14 | #define lbs_pr_info(format, args...) \ | ||
15 | printk(KERN_INFO DRV_NAME": " format, ## args) | ||
16 | #define lbs_pr_err(format, args...) \ | ||
17 | printk(KERN_ERR DRV_NAME": " format, ## args) | ||
18 | #define lbs_pr_alert(format, args...) \ | ||
19 | printk(KERN_ALERT DRV_NAME": " format, ## args) | ||
20 | |||
21 | #ifdef DEBUG | ||
22 | #define lbs_pr_debug(level, format, args...) \ | ||
23 | do { if (libertas_debug >= level) \ | ||
24 | printk(KERN_INFO DRV_NAME": " format, ##args); } while (0) | ||
25 | #define lbs_dev_dbg(level, device, format, args...) \ | ||
26 | lbs_pr_debug(level, "%s: " format, \ | ||
27 | (device)->bus_id , ## args) | ||
28 | |||
29 | static inline void lbs_dbg_hex(char *prompt, u8 * buf, int len) | ||
30 | { | ||
31 | int i = 0; | ||
32 | |||
33 | if (!libertas_debug) | ||
34 | return; | ||
35 | |||
36 | printk(KERN_DEBUG "%s: ", prompt); | ||
37 | for (i = 1; i <= len; i++) { | ||
38 | printk(KERN_DEBUG "%02x ", (u8) * buf); | ||
39 | buf++; | ||
40 | } | ||
41 | printk("\n"); | ||
42 | } | ||
43 | #else | ||
44 | #define lbs_pr_debug(level, format, args...) do {} while (0) | ||
45 | #define lbs_dev_dbg(level, device, format, args...) do {} while (0) | ||
46 | #define lbs_dbg_hex(x,y,z) do {} while (0) | ||
47 | #endif | ||
48 | |||
49 | #define ENTER() lbs_pr_debug(1, "Enter: %s, %s:%i\n", \ | ||
50 | __FUNCTION__, __FILE__, __LINE__) | ||
51 | #define LEAVE() lbs_pr_debug(1, "Leave: %s, %s:%i\n", \ | ||
52 | __FUNCTION__, __FILE__, __LINE__) | ||
53 | |||
54 | /** Buffer Constants */ | ||
55 | |||
56 | /* The size of SQ memory PPA, DPA are 8 DWORDs, that keep the physical | ||
57 | * addresses of TxPD buffers. Station has only 8 TxPD available, Whereas | ||
58 | * driver has more local TxPDs. Each TxPD on the host memory is associated | ||
59 | * with a Tx control node. The driver maintains 8 RxPD descriptors for | ||
60 | * station firmware to store Rx packet information. | ||
61 | * | ||
62 | * Current version of MAC has a 32x6 multicast address buffer. | ||
63 | * | ||
64 | * 802.11b can have up to 14 channels, the driver keeps the | ||
65 | * BSSID(MAC address) of each APs or Ad hoc stations it has sensed. | ||
66 | */ | ||
67 | |||
68 | #define MRVDRV_MAX_MULTICAST_LIST_SIZE 32 | ||
69 | #define MRVDRV_NUM_OF_CMD_BUFFER 10 | ||
70 | #define MRVDRV_SIZE_OF_CMD_BUFFER (2 * 1024) | ||
71 | #define MRVDRV_MAX_CHANNEL_SIZE 14 | ||
72 | #define MRVDRV_MAX_BSSID_LIST 64 | ||
73 | #define MRVDRV_ASSOCIATION_TIME_OUT 255 | ||
74 | #define MRVDRV_SNAP_HEADER_LEN 8 | ||
75 | |||
76 | #define WLAN_UPLD_SIZE 2312 | ||
77 | #define DEV_NAME_LEN 32 | ||
78 | |||
79 | /** Misc constants */ | ||
80 | /* This section defines 802.11 specific contants */ | ||
81 | |||
82 | #define MRVDRV_MAX_BSS_DESCRIPTS 16 | ||
83 | #define MRVDRV_MAX_REGION_CODE 6 | ||
84 | |||
85 | #define MRVDRV_IGNORE_MULTIPLE_DTIM 0xfffe | ||
86 | #define MRVDRV_MIN_MULTIPLE_DTIM 1 | ||
87 | #define MRVDRV_MAX_MULTIPLE_DTIM 5 | ||
88 | #define MRVDRV_DEFAULT_MULTIPLE_DTIM 1 | ||
89 | |||
90 | #define MRVDRV_DEFAULT_LISTEN_INTERVAL 10 | ||
91 | |||
92 | #define MRVDRV_CHANNELS_PER_SCAN 4 | ||
93 | #define MRVDRV_MAX_CHANNELS_PER_SCAN 14 | ||
94 | |||
95 | #define MRVDRV_DEBUG_RX_PATH 0x00000001 | ||
96 | #define MRVDRV_DEBUG_TX_PATH 0x00000002 | ||
97 | |||
98 | #define MRVDRV_MIN_BEACON_INTERVAL 20 | ||
99 | #define MRVDRV_MAX_BEACON_INTERVAL 1000 | ||
100 | #define MRVDRV_BEACON_INTERVAL 100 | ||
101 | |||
102 | /** TxPD status */ | ||
103 | |||
104 | /* Station firmware use TxPD status field to report final Tx transmit | ||
105 | * result, Bit masks are used to present combined situations. | ||
106 | */ | ||
107 | |||
108 | #define MRVDRV_TxPD_POWER_MGMT_NULL_PACKET 0x01 | ||
109 | #define MRVDRV_TxPD_POWER_MGMT_LAST_PACKET 0x08 | ||
110 | |||
111 | /** Tx mesh flag */ | ||
112 | /* Currently we are using normal WDS flag as mesh flag. | ||
113 | * TODO: change to proper mesh flag when MAC understands it. | ||
114 | */ | ||
115 | #define TxPD_CONTROL_WDS_FRAME (1<<17) | ||
116 | #define TxPD_MESH_FRAME TxPD_CONTROL_WDS_FRAME | ||
117 | |||
118 | /** RxPD status */ | ||
119 | |||
120 | #define MRVDRV_RXPD_STATUS_OK 0x0001 | ||
121 | |||
122 | /** RxPD status - Received packet types */ | ||
123 | /** Rx mesh flag */ | ||
124 | /* Currently we are using normal WDS flag as mesh flag. | ||
125 | * TODO: change to proper mesh flag when MAC understands it. | ||
126 | */ | ||
127 | #define RxPD_CONTROL_WDS_FRAME (0x40) | ||
128 | #define RxPD_MESH_FRAME RxPD_CONTROL_WDS_FRAME | ||
129 | |||
130 | /** RSSI-related defines */ | ||
131 | /* RSSI constants are used to implement 802.11 RSSI threshold | ||
132 | * indication. if the Rx packet signal got too weak for 5 consecutive | ||
133 | * times, miniport driver (driver) will report this event to wrapper | ||
134 | */ | ||
135 | |||
136 | #define MRVDRV_NF_DEFAULT_SCAN_VALUE (-96) | ||
137 | |||
138 | /** RTS/FRAG related defines */ | ||
139 | #define MRVDRV_RTS_MIN_VALUE 0 | ||
140 | #define MRVDRV_RTS_MAX_VALUE 2347 | ||
141 | #define MRVDRV_FRAG_MIN_VALUE 256 | ||
142 | #define MRVDRV_FRAG_MAX_VALUE 2346 | ||
143 | |||
144 | /* This is for firmware specific length */ | ||
145 | #define EXTRA_LEN 36 | ||
146 | |||
147 | #define MRVDRV_ETH_TX_PACKET_BUFFER_SIZE \ | ||
148 | (ETH_FRAME_LEN + sizeof(struct txpd) + EXTRA_LEN) | ||
149 | |||
150 | #define MRVDRV_ETH_RX_PACKET_BUFFER_SIZE \ | ||
151 | (ETH_FRAME_LEN + sizeof(struct rxpd) \ | ||
152 | + MRVDRV_SNAP_HEADER_LEN + EXTRA_LEN) | ||
153 | |||
154 | #define CMD_F_HOSTCMD (1 << 0) | ||
155 | #define FW_CAPINFO_WPA (1 << 0) | ||
156 | |||
157 | /** WPA key LENGTH*/ | ||
158 | #define MRVL_MAX_KEY_WPA_KEY_LENGTH 32 | ||
159 | |||
160 | #define KEY_LEN_WPA_AES 16 | ||
161 | #define KEY_LEN_WPA_TKIP 32 | ||
162 | #define KEY_LEN_WEP_104 13 | ||
163 | #define KEY_LEN_WEP_40 5 | ||
164 | |||
165 | #define RF_ANTENNA_1 0x1 | ||
166 | #define RF_ANTENNA_2 0x2 | ||
167 | #define RF_ANTENNA_AUTO 0xFFFF | ||
168 | |||
169 | #define BAND_B (0x01) | ||
170 | #define BAND_G (0x02) | ||
171 | #define ALL_802_11_BANDS (BAND_B | BAND_G) | ||
172 | |||
173 | /** MACRO DEFINITIONS */ | ||
174 | #define CAL_NF(NF) ((s32)(-(s32)(NF))) | ||
175 | #define CAL_RSSI(SNR, NF) ((s32)((s32)(SNR) + CAL_NF(NF))) | ||
176 | #define SCAN_RSSI(RSSI) (0x100 - ((u8)(RSSI))) | ||
177 | |||
178 | #define DEFAULT_BCN_AVG_FACTOR 8 | ||
179 | #define DEFAULT_DATA_AVG_FACTOR 8 | ||
180 | #define AVG_SCALE 100 | ||
181 | #define CAL_AVG_SNR_NF(AVG, SNRNF, N) \ | ||
182 | (((AVG) == 0) ? ((u16)(SNRNF) * AVG_SCALE) : \ | ||
183 | ((((int)(AVG) * (N -1)) + ((u16)(SNRNF) * \ | ||
184 | AVG_SCALE)) / N)) | ||
185 | |||
186 | #define B_SUPPORTED_RATES 8 | ||
187 | #define G_SUPPORTED_RATES 14 | ||
188 | |||
189 | #define WLAN_SUPPORTED_RATES 14 | ||
190 | |||
191 | #define MAX_LEDS 8 | ||
192 | |||
193 | #define IS_MESH_FRAME(x) (x->cb[6]) | ||
194 | #define SET_MESH_FRAME(x) (x->cb[6]=1) | ||
195 | #define UNSET_MESH_FRAME(x) (x->cb[6]=0) | ||
196 | |||
197 | /** Global Variable Declaration */ | ||
198 | typedef struct _wlan_private wlan_private; | ||
199 | typedef struct _wlan_adapter wlan_adapter; | ||
200 | extern const char libertas_driver_version[]; | ||
201 | extern u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE]; | ||
202 | |||
203 | extern u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES]; | ||
204 | |||
205 | extern u8 libertas_supported_rates[G_SUPPORTED_RATES]; | ||
206 | |||
207 | extern u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES]; | ||
208 | |||
209 | extern u8 libertas_adhoc_rates_b[4]; | ||
210 | |||
211 | /** ENUM definition*/ | ||
212 | /** SNRNF_TYPE */ | ||
213 | enum SNRNF_TYPE { | ||
214 | TYPE_BEACON = 0, | ||
215 | TYPE_RXPD, | ||
216 | MAX_TYPE_B | ||
217 | }; | ||
218 | |||
219 | /** SNRNF_DATA*/ | ||
220 | enum SNRNF_DATA { | ||
221 | TYPE_NOAVG = 0, | ||
222 | TYPE_AVG, | ||
223 | MAX_TYPE_AVG | ||
224 | }; | ||
225 | |||
226 | /** WLAN_802_11_AUTH_ALG*/ | ||
227 | enum WLAN_802_11_AUTH_ALG { | ||
228 | AUTH_ALG_OPEN_SYSTEM = 1, | ||
229 | AUTH_ALG_SHARED_KEY = 2, | ||
230 | AUTH_ALG_NETWORK_EAP = 8, | ||
231 | }; | ||
232 | |||
233 | /** WLAN_802_1X_AUTH_ALG */ | ||
234 | enum WLAN_802_1X_AUTH_ALG { | ||
235 | WLAN_1X_AUTH_ALG_NONE = 1, | ||
236 | WLAN_1X_AUTH_ALG_LEAP = 2, | ||
237 | WLAN_1X_AUTH_ALG_TLS = 4, | ||
238 | WLAN_1X_AUTH_ALG_TTLS = 8, | ||
239 | WLAN_1X_AUTH_ALG_MD5 = 16, | ||
240 | }; | ||
241 | |||
242 | /** WLAN_802_11_ENCRYPTION_MODE */ | ||
243 | enum WLAN_802_11_ENCRYPTION_MODE { | ||
244 | CIPHER_NONE, | ||
245 | CIPHER_WEP40, | ||
246 | CIPHER_TKIP, | ||
247 | CIPHER_CCMP, | ||
248 | CIPHER_WEP104, | ||
249 | }; | ||
250 | |||
251 | /** WLAN_802_11_POWER_MODE */ | ||
252 | enum WLAN_802_11_POWER_MODE { | ||
253 | wlan802_11powermodecam, | ||
254 | wlan802_11powermodemax_psp, | ||
255 | wlan802_11Powermodefast_psp, | ||
256 | /*not a real mode, defined as an upper bound */ | ||
257 | wlan802_11powemodemax | ||
258 | }; | ||
259 | |||
260 | /** PS_STATE */ | ||
261 | enum PS_STATE { | ||
262 | PS_STATE_FULL_POWER, | ||
263 | PS_STATE_AWAKE, | ||
264 | PS_STATE_PRE_SLEEP, | ||
265 | PS_STATE_SLEEP | ||
266 | }; | ||
267 | |||
268 | /** DNLD_STATE */ | ||
269 | enum DNLD_STATE { | ||
270 | DNLD_RES_RECEIVED, | ||
271 | DNLD_DATA_SENT, | ||
272 | DNLD_CMD_SENT | ||
273 | }; | ||
274 | |||
275 | /** WLAN_MEDIA_STATE */ | ||
276 | enum WLAN_MEDIA_STATE { | ||
277 | libertas_connected, | ||
278 | libertas_disconnected | ||
279 | }; | ||
280 | |||
281 | /** WLAN_802_11_PRIVACY_FILTER */ | ||
282 | enum WLAN_802_11_PRIVACY_FILTER { | ||
283 | wlan802_11privfilteracceptall, | ||
284 | wlan802_11privfilter8021xWEP | ||
285 | }; | ||
286 | |||
287 | /** mv_ms_type */ | ||
288 | enum mv_ms_type { | ||
289 | MVMS_DAT = 0, | ||
290 | MVMS_CMD = 1, | ||
291 | MVMS_TXDONE = 2, | ||
292 | MVMS_EVENT | ||
293 | }; | ||
294 | |||
295 | /** WLAN_802_11_NETWORK_INFRASTRUCTURE */ | ||
296 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE { | ||
297 | wlan802_11ibss, | ||
298 | wlan802_11infrastructure, | ||
299 | wlan802_11autounknown, | ||
300 | /*defined as upper bound */ | ||
301 | wlan802_11infrastructuremax | ||
302 | }; | ||
303 | |||
304 | /** WLAN_802_11_AUTHENTICATION_MODE */ | ||
305 | enum WLAN_802_11_AUTHENTICATION_MODE { | ||
306 | wlan802_11authmodeopen = 0x00, | ||
307 | wlan802_11authmodeshared = 0x01, | ||
308 | wlan802_11authmodenetworkEAP = 0x80, | ||
309 | }; | ||
310 | |||
311 | /** WLAN_802_11_WEP_STATUS */ | ||
312 | enum WLAN_802_11_WEP_STATUS { | ||
313 | wlan802_11WEPenabled, | ||
314 | wlan802_11WEPdisabled, | ||
315 | }; | ||
316 | |||
317 | /** SNMP_MIB_INDEX_e */ | ||
318 | enum SNMP_MIB_INDEX_e { | ||
319 | desired_bsstype_i = 0, | ||
320 | op_rateset_i, | ||
321 | bcnperiod_i, | ||
322 | dtimperiod_i, | ||
323 | assocrsp_timeout_i, | ||
324 | rtsthresh_i, | ||
325 | short_retrylim_i, | ||
326 | long_retrylim_i, | ||
327 | fragthresh_i, | ||
328 | dot11d_i, | ||
329 | dot11h_i, | ||
330 | manufid_i, | ||
331 | prodID_i, | ||
332 | manuf_oui_i, | ||
333 | manuf_name_i, | ||
334 | manuf_prodname_i, | ||
335 | manuf_prodver_i, | ||
336 | }; | ||
337 | |||
338 | /** KEY_TYPE_ID */ | ||
339 | enum KEY_TYPE_ID { | ||
340 | KEY_TYPE_ID_WEP = 0, | ||
341 | KEY_TYPE_ID_TKIP, | ||
342 | KEY_TYPE_ID_AES | ||
343 | }; | ||
344 | |||
345 | /** KEY_INFO_WPA (applies to both TKIP and AES/CCMP) */ | ||
346 | enum KEY_INFO_WPA { | ||
347 | KEY_INFO_WPA_MCAST = 0x01, | ||
348 | KEY_INFO_WPA_UNICAST = 0x02, | ||
349 | KEY_INFO_WPA_ENABLED = 0x04 | ||
350 | }; | ||
351 | |||
352 | /** SNMP_MIB_VALUE_e */ | ||
353 | enum SNMP_MIB_VALUE_e { | ||
354 | SNMP_MIB_VALUE_INFRA = 1, | ||
355 | SNMP_MIB_VALUE_ADHOC | ||
356 | }; | ||
357 | |||
358 | /* Default values for fwt commands. */ | ||
359 | #define FWT_DEFAULT_METRIC 0 | ||
360 | #define FWT_DEFAULT_DIR 1 | ||
361 | #define FWT_DEFAULT_SSN 0xffffffff | ||
362 | #define FWT_DEFAULT_DSN 0 | ||
363 | #define FWT_DEFAULT_HOPCOUNT 0 | ||
364 | #define FWT_DEFAULT_TTL 0 | ||
365 | #define FWT_DEFAULT_EXPIRATION 0 | ||
366 | #define FWT_DEFAULT_SLEEPMODE 0 | ||
367 | #define FWT_DEFAULT_SNR 0 | ||
368 | |||
369 | #endif /* _WLAN_DEFS_H_ */ | ||
diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h new file mode 100644 index 000000000000..b1f876f9693b --- /dev/null +++ b/drivers/net/wireless/libertas/dev.h | |||
@@ -0,0 +1,403 @@ | |||
1 | /** | ||
2 | * This file contains definitions and data structures specific | ||
3 | * to Marvell 802.11 NIC. It contains the Device Information | ||
4 | * structure wlan_adapter. | ||
5 | */ | ||
6 | #ifndef _WLAN_DEV_H_ | ||
7 | #define _WLAN_DEV_H_ | ||
8 | |||
9 | #include <linux/netdevice.h> | ||
10 | #include <linux/wireless.h> | ||
11 | #include <linux/ethtool.h> | ||
12 | #include <linux/debugfs.h> | ||
13 | |||
14 | #include "defs.h" | ||
15 | #include "scan.h" | ||
16 | #include "thread.h" | ||
17 | |||
18 | extern struct ethtool_ops libertas_ethtool_ops; | ||
19 | |||
20 | #define MAX_BSSID_PER_CHANNEL 16 | ||
21 | |||
22 | #define NR_TX_QUEUE 3 | ||
23 | |||
24 | /* For the extended Scan */ | ||
25 | #define MAX_EXTENDED_SCAN_BSSID_LIST MAX_BSSID_PER_CHANNEL * \ | ||
26 | MRVDRV_MAX_CHANNEL_SIZE + 1 | ||
27 | |||
28 | #define MAX_REGION_CHANNEL_NUM 2 | ||
29 | |||
30 | /** Chan-freq-TxPower mapping table*/ | ||
31 | struct chan_freq_power { | ||
32 | /** channel Number */ | ||
33 | u16 channel; | ||
34 | /** frequency of this channel */ | ||
35 | u32 freq; | ||
36 | /** Max allowed Tx power level */ | ||
37 | u16 maxtxpower; | ||
38 | /** TRUE:channel unsupported; FLASE:supported*/ | ||
39 | u8 unsupported; | ||
40 | }; | ||
41 | |||
42 | /** region-band mapping table*/ | ||
43 | struct region_channel { | ||
44 | /** TRUE if this entry is valid */ | ||
45 | u8 valid; | ||
46 | /** region code for US, Japan ... */ | ||
47 | u8 region; | ||
48 | /** band B/G/A, used for BAND_CONFIG cmd */ | ||
49 | u8 band; | ||
50 | /** Actual No. of elements in the array below */ | ||
51 | u8 nrcfp; | ||
52 | /** chan-freq-txpower mapping table*/ | ||
53 | struct chan_freq_power *CFP; | ||
54 | }; | ||
55 | |||
56 | struct wlan_802_11_security { | ||
57 | u8 WPAenabled; | ||
58 | u8 WPA2enabled; | ||
59 | enum WLAN_802_11_WEP_STATUS WEPstatus; | ||
60 | enum WLAN_802_11_AUTHENTICATION_MODE authmode; | ||
61 | enum WLAN_802_1X_AUTH_ALG auth1xalg; | ||
62 | enum WLAN_802_11_ENCRYPTION_MODE Encryptionmode; | ||
63 | }; | ||
64 | |||
65 | /** Current Basic Service Set State Structure */ | ||
66 | struct current_bss_params { | ||
67 | struct bss_descriptor bssdescriptor; | ||
68 | /** bssid */ | ||
69 | u8 bssid[ETH_ALEN]; | ||
70 | /** ssid */ | ||
71 | struct WLAN_802_11_SSID ssid; | ||
72 | |||
73 | /** band */ | ||
74 | u8 band; | ||
75 | /** channel */ | ||
76 | u8 channel; | ||
77 | /** number of rates supported */ | ||
78 | int numofrates; | ||
79 | /** supported rates*/ | ||
80 | u8 datarates[WLAN_SUPPORTED_RATES]; | ||
81 | }; | ||
82 | |||
83 | /** sleep_params */ | ||
84 | struct sleep_params { | ||
85 | u16 sp_error; | ||
86 | u16 sp_offset; | ||
87 | u16 sp_stabletime; | ||
88 | u8 sp_calcontrol; | ||
89 | u8 sp_extsleepclk; | ||
90 | u16 sp_reserved; | ||
91 | }; | ||
92 | |||
93 | /** Data structure for the Marvell WLAN device */ | ||
94 | typedef struct _wlan_dev { | ||
95 | /** device name */ | ||
96 | char name[DEV_NAME_LEN]; | ||
97 | /** card pointer */ | ||
98 | void *card; | ||
99 | /** IO port */ | ||
100 | u32 ioport; | ||
101 | /** Upload received */ | ||
102 | u32 upld_rcv; | ||
103 | /** Upload type */ | ||
104 | u32 upld_typ; | ||
105 | /** Upload length */ | ||
106 | u32 upld_len; | ||
107 | /** netdev pointer */ | ||
108 | struct net_device *netdev; | ||
109 | /* Upload buffer */ | ||
110 | u8 upld_buf[WLAN_UPLD_SIZE]; | ||
111 | /* Download sent: | ||
112 | bit0 1/0=data_sent/data_tx_done, | ||
113 | bit1 1/0=cmd_sent/cmd_tx_done, | ||
114 | all other bits reserved 0 */ | ||
115 | u8 dnld_sent; | ||
116 | } wlan_dev_t, *pwlan_dev_t; | ||
117 | |||
118 | /* Mesh statistics */ | ||
119 | struct wlan_mesh_stats { | ||
120 | u32 fwd_bcast_cnt; /* Fwd: Broadcast counter */ | ||
121 | u32 fwd_unicast_cnt; /* Fwd: Unicast counter */ | ||
122 | u32 fwd_drop_ttl; /* Fwd: TTL zero */ | ||
123 | u32 fwd_drop_rbt; /* Fwd: Recently Broadcasted */ | ||
124 | u32 fwd_drop_noroute; /* Fwd: No route to Destination */ | ||
125 | u32 fwd_drop_nobuf; /* Fwd: Run out of internal buffers */ | ||
126 | u32 drop_blind; /* Rx: Dropped by blinding table */ | ||
127 | }; | ||
128 | |||
129 | /** Private structure for the MV device */ | ||
130 | struct _wlan_private { | ||
131 | int open; | ||
132 | int mesh_open; | ||
133 | int infra_open; | ||
134 | |||
135 | wlan_adapter *adapter; | ||
136 | wlan_dev_t wlan_dev; | ||
137 | |||
138 | struct net_device_stats stats; | ||
139 | struct net_device *mesh_dev ; /* Virtual device */ | ||
140 | |||
141 | struct iw_statistics wstats; | ||
142 | struct wlan_mesh_stats mstats; | ||
143 | struct dentry *debugfs_dir; | ||
144 | struct dentry *debugfs_debug; | ||
145 | struct dentry *debugfs_files[6]; | ||
146 | |||
147 | struct dentry *events_dir; | ||
148 | struct dentry *debugfs_events_files[6]; | ||
149 | |||
150 | struct dentry *regs_dir; | ||
151 | struct dentry *debugfs_regs_files[6]; | ||
152 | |||
153 | u32 mac_offset; | ||
154 | u32 bbp_offset; | ||
155 | u32 rf_offset; | ||
156 | |||
157 | const struct firmware *firmware; | ||
158 | struct device *hotplug_device; | ||
159 | |||
160 | /** thread to service interrupts */ | ||
161 | struct wlan_thread mainthread; | ||
162 | |||
163 | struct delayed_work assoc_work; | ||
164 | struct workqueue_struct *assoc_thread; | ||
165 | }; | ||
166 | |||
167 | /** Association request | ||
168 | * | ||
169 | * Encapsulates all the options that describe a specific assocation request | ||
170 | * or configuration of the wireless card's radio, mode, and security settings. | ||
171 | */ | ||
172 | struct assoc_request { | ||
173 | #define ASSOC_FLAG_SSID 1 | ||
174 | #define ASSOC_FLAG_CHANNEL 2 | ||
175 | #define ASSOC_FLAG_MODE 3 | ||
176 | #define ASSOC_FLAG_BSSID 4 | ||
177 | #define ASSOC_FLAG_WEP_KEYS 5 | ||
178 | #define ASSOC_FLAG_WEP_TX_KEYIDX 6 | ||
179 | #define ASSOC_FLAG_WPA_MCAST_KEY 7 | ||
180 | #define ASSOC_FLAG_WPA_UCAST_KEY 8 | ||
181 | #define ASSOC_FLAG_SECINFO 9 | ||
182 | #define ASSOC_FLAG_WPA_IE 10 | ||
183 | unsigned long flags; | ||
184 | |||
185 | struct WLAN_802_11_SSID ssid; | ||
186 | u8 channel; | ||
187 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode; | ||
188 | u8 bssid[ETH_ALEN]; | ||
189 | |||
190 | /** WEP keys */ | ||
191 | struct WLAN_802_11_KEY wep_keys[4]; | ||
192 | u16 wep_tx_keyidx; | ||
193 | |||
194 | /** WPA keys */ | ||
195 | struct WLAN_802_11_KEY wpa_mcast_key; | ||
196 | struct WLAN_802_11_KEY wpa_unicast_key; | ||
197 | |||
198 | struct wlan_802_11_security secinfo; | ||
199 | |||
200 | /** WPA Information Elements*/ | ||
201 | #define MAX_WPA_IE_LEN 64 | ||
202 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
203 | u8 wpa_ie_len; | ||
204 | }; | ||
205 | |||
206 | /** Wlan adapter data structure*/ | ||
207 | struct _wlan_adapter { | ||
208 | /** STATUS variables */ | ||
209 | u32 fwreleasenumber; | ||
210 | u32 fwcapinfo; | ||
211 | /* protected with big lock */ | ||
212 | |||
213 | struct mutex lock; | ||
214 | |||
215 | u8 tmptxbuf[WLAN_UPLD_SIZE]; | ||
216 | /* protected by hard_start_xmit serialization */ | ||
217 | |||
218 | /** command-related variables */ | ||
219 | u16 seqnum; | ||
220 | /* protected by big lock */ | ||
221 | |||
222 | struct cmd_ctrl_node *cmd_array; | ||
223 | /** Current command */ | ||
224 | struct cmd_ctrl_node *cur_cmd; | ||
225 | int cur_cmd_retcode; | ||
226 | /** command Queues */ | ||
227 | /** Free command buffers */ | ||
228 | struct list_head cmdfreeq; | ||
229 | /** Pending command buffers */ | ||
230 | struct list_head cmdpendingq; | ||
231 | |||
232 | wait_queue_head_t cmd_pending; | ||
233 | u8 nr_cmd_pending; | ||
234 | /* command related variables protected by adapter->driver_lock */ | ||
235 | |||
236 | /** Async and Sync Event variables */ | ||
237 | u32 intcounter; | ||
238 | u32 eventcause; | ||
239 | u8 nodename[16]; /* nickname */ | ||
240 | |||
241 | /** spin locks */ | ||
242 | spinlock_t driver_lock; | ||
243 | |||
244 | /** Timers */ | ||
245 | struct timer_list command_timer; | ||
246 | |||
247 | /* TX queue used in PS mode */ | ||
248 | spinlock_t txqueue_lock; | ||
249 | struct sk_buff *tx_queue_ps[NR_TX_QUEUE]; | ||
250 | unsigned int tx_queue_idx; | ||
251 | |||
252 | u8 hisregcpy; | ||
253 | |||
254 | /** current ssid/bssid related parameters*/ | ||
255 | struct current_bss_params curbssparams; | ||
256 | |||
257 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode; | ||
258 | |||
259 | struct bss_descriptor *pattemptedbssdesc; | ||
260 | |||
261 | struct WLAN_802_11_SSID previousssid; | ||
262 | u8 previousbssid[ETH_ALEN]; | ||
263 | |||
264 | struct bss_descriptor *scantable; | ||
265 | u32 numinscantable; | ||
266 | |||
267 | u8 scantype; | ||
268 | u32 scanmode; | ||
269 | |||
270 | u16 beaconperiod; | ||
271 | u8 adhoccreate; | ||
272 | |||
273 | /** capability Info used in Association, start, join */ | ||
274 | struct ieeetypes_capinfo capinfo; | ||
275 | |||
276 | /** MAC address information */ | ||
277 | u8 current_addr[ETH_ALEN]; | ||
278 | u8 multicastlist[MRVDRV_MAX_MULTICAST_LIST_SIZE][ETH_ALEN]; | ||
279 | u32 nr_of_multicastmacaddr; | ||
280 | |||
281 | /** 802.11 statistics */ | ||
282 | // struct cmd_DS_802_11_GET_STAT wlan802_11Stat; | ||
283 | |||
284 | u16 enablehwauto; | ||
285 | u16 ratebitmap; | ||
286 | /** control G rates */ | ||
287 | u8 adhoc_grate_enabled; | ||
288 | |||
289 | u32 txantenna; | ||
290 | u32 rxantenna; | ||
291 | |||
292 | u8 adhocchannel; | ||
293 | u32 fragthsd; | ||
294 | u32 rtsthsd; | ||
295 | |||
296 | u32 datarate; | ||
297 | u8 is_datarate_auto; | ||
298 | |||
299 | u16 listeninterval; | ||
300 | u16 prescan; | ||
301 | u8 txretrycount; | ||
302 | |||
303 | /** Tx-related variables (for single packet tx) */ | ||
304 | struct sk_buff *currenttxskb; | ||
305 | u16 TxLockFlag; | ||
306 | |||
307 | /** NIC Operation characteristics */ | ||
308 | u16 currentpacketfilter; | ||
309 | u32 connect_status; | ||
310 | u16 regioncode; | ||
311 | u16 regiontableindex; | ||
312 | u16 txpowerlevel; | ||
313 | |||
314 | /** POWER MANAGEMENT AND PnP SUPPORT */ | ||
315 | u8 surpriseremoved; | ||
316 | u16 atimwindow; | ||
317 | |||
318 | u16 psmode; /* Wlan802_11PowermodeCAM=disable | ||
319 | Wlan802_11PowermodeMAX_PSP=enable */ | ||
320 | u16 multipledtim; | ||
321 | u32 psstate; | ||
322 | u8 needtowakeup; | ||
323 | |||
324 | struct PS_CMD_ConfirmSleep libertas_ps_confirm_sleep; | ||
325 | u16 locallisteninterval; | ||
326 | u16 nullpktinterval; | ||
327 | |||
328 | struct assoc_request * assoc_req; | ||
329 | |||
330 | /** Encryption parameter */ | ||
331 | struct wlan_802_11_security secinfo; | ||
332 | |||
333 | /** WEP keys */ | ||
334 | struct WLAN_802_11_KEY wep_keys[4]; | ||
335 | u16 wep_tx_keyidx; | ||
336 | |||
337 | /** WPA keys */ | ||
338 | struct WLAN_802_11_KEY wpa_mcast_key; | ||
339 | struct WLAN_802_11_KEY wpa_unicast_key; | ||
340 | |||
341 | /** WPA Information Elements*/ | ||
342 | #define MAX_WPA_IE_LEN 64 | ||
343 | u8 wpa_ie[MAX_WPA_IE_LEN]; | ||
344 | u8 wpa_ie_len; | ||
345 | |||
346 | u16 rxantennamode; | ||
347 | u16 txantennamode; | ||
348 | |||
349 | /** Requested Signal Strength*/ | ||
350 | u16 bcn_avg_factor; | ||
351 | u16 data_avg_factor; | ||
352 | u16 SNR[MAX_TYPE_B][MAX_TYPE_AVG]; | ||
353 | u16 NF[MAX_TYPE_B][MAX_TYPE_AVG]; | ||
354 | u8 RSSI[MAX_TYPE_B][MAX_TYPE_AVG]; | ||
355 | u8 rawSNR[DEFAULT_DATA_AVG_FACTOR]; | ||
356 | u8 rawNF[DEFAULT_DATA_AVG_FACTOR]; | ||
357 | u16 nextSNRNF; | ||
358 | u16 numSNRNF; | ||
359 | u16 rxpd_rate; | ||
360 | |||
361 | u8 radioon; | ||
362 | u32 preamble; | ||
363 | |||
364 | /** Multi bands Parameter*/ | ||
365 | u8 libertas_supported_rates[G_SUPPORTED_RATES]; | ||
366 | |||
367 | /** Blue Tooth Co-existence Arbitration */ | ||
368 | |||
369 | /** sleep_params */ | ||
370 | struct sleep_params sp; | ||
371 | |||
372 | /** RF calibration data */ | ||
373 | |||
374 | #define MAX_REGION_CHANNEL_NUM 2 | ||
375 | /** region channel data */ | ||
376 | struct region_channel region_channel[MAX_REGION_CHANNEL_NUM]; | ||
377 | |||
378 | struct region_channel universal_channel[MAX_REGION_CHANNEL_NUM]; | ||
379 | |||
380 | /** 11D and Domain Regulatory Data */ | ||
381 | struct wlan_802_11d_domain_reg domainreg; | ||
382 | struct parsed_region_chan_11d parsed_region_chan; | ||
383 | |||
384 | /** FSM variable for 11d support */ | ||
385 | u32 enable11d; | ||
386 | |||
387 | /** MISCELLANEOUS */ | ||
388 | u8 *prdeeprom; | ||
389 | struct wlan_offset_value offsetvalue; | ||
390 | |||
391 | struct cmd_ds_802_11_get_log logmsg; | ||
392 | u16 scanprobes; | ||
393 | |||
394 | u32 pkttxctrl; | ||
395 | |||
396 | u16 txrate; | ||
397 | u32 linkmode; | ||
398 | u32 radiomode; | ||
399 | u32 debugmode; | ||
400 | u8 fw_ready; | ||
401 | }; | ||
402 | |||
403 | #endif /* _WLAN_DEV_H_ */ | ||
diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c new file mode 100644 index 000000000000..0064de542963 --- /dev/null +++ b/drivers/net/wireless/libertas/ethtool.c | |||
@@ -0,0 +1,184 @@ | |||
1 | |||
2 | #include <linux/netdevice.h> | ||
3 | #include <linux/ethtool.h> | ||
4 | #include <linux/delay.h> | ||
5 | |||
6 | #include "host.h" | ||
7 | #include "sbi.h" | ||
8 | #include "decl.h" | ||
9 | #include "defs.h" | ||
10 | #include "dev.h" | ||
11 | #include "join.h" | ||
12 | #include "wext.h" | ||
13 | static const char * mesh_stat_strings[]= { | ||
14 | "drop_duplicate_bcast", | ||
15 | "drop_ttl_zero", | ||
16 | "drop_no_fwd_route", | ||
17 | "drop_no_buffers", | ||
18 | "fwded_unicast_cnt", | ||
19 | "fwded_bcast_cnt", | ||
20 | "drop_blind_table" | ||
21 | }; | ||
22 | |||
23 | static void libertas_ethtool_get_drvinfo(struct net_device *dev, | ||
24 | struct ethtool_drvinfo *info) | ||
25 | { | ||
26 | wlan_private *priv = (wlan_private *) dev->priv; | ||
27 | char fwver[32]; | ||
28 | |||
29 | libertas_get_fwversion(priv->adapter, fwver, sizeof(fwver) - 1); | ||
30 | |||
31 | strcpy(info->driver, "libertas"); | ||
32 | strcpy(info->version, libertas_driver_version); | ||
33 | strcpy(info->fw_version, fwver); | ||
34 | } | ||
35 | |||
36 | /* All 8388 parts have 16KiB EEPROM size at the time of writing. | ||
37 | * In case that changes this needs fixing. | ||
38 | */ | ||
39 | #define LIBERTAS_EEPROM_LEN 16384 | ||
40 | |||
41 | static int libertas_ethtool_get_eeprom_len(struct net_device *dev) | ||
42 | { | ||
43 | return LIBERTAS_EEPROM_LEN; | ||
44 | } | ||
45 | |||
46 | static int libertas_ethtool_get_eeprom(struct net_device *dev, | ||
47 | struct ethtool_eeprom *eeprom, u8 * bytes) | ||
48 | { | ||
49 | wlan_private *priv = (wlan_private *) dev->priv; | ||
50 | wlan_adapter *adapter = priv->adapter; | ||
51 | struct wlan_ioctl_regrdwr regctrl; | ||
52 | char *ptr; | ||
53 | int ret; | ||
54 | |||
55 | regctrl.action = 0; | ||
56 | regctrl.offset = eeprom->offset; | ||
57 | regctrl.NOB = eeprom->len; | ||
58 | |||
59 | if (eeprom->offset + eeprom->len > LIBERTAS_EEPROM_LEN) | ||
60 | return -EINVAL; | ||
61 | |||
62 | // mutex_lock(&priv->mutex); | ||
63 | |||
64 | adapter->prdeeprom = | ||
65 | (char *)kmalloc(eeprom->len+sizeof(regctrl), GFP_KERNEL); | ||
66 | if (!adapter->prdeeprom) | ||
67 | return -ENOMEM; | ||
68 | memcpy(adapter->prdeeprom, ®ctrl, sizeof(regctrl)); | ||
69 | |||
70 | /* +14 is for action, offset, and NOB in | ||
71 | * response */ | ||
72 | lbs_pr_debug(1, "action:%d offset: %x NOB: %02x\n", | ||
73 | regctrl.action, regctrl.offset, regctrl.NOB); | ||
74 | |||
75 | ret = libertas_prepare_and_send_command(priv, | ||
76 | cmd_802_11_eeprom_access, | ||
77 | regctrl.action, | ||
78 | cmd_option_waitforrsp, 0, | ||
79 | ®ctrl); | ||
80 | |||
81 | if (ret) { | ||
82 | if (adapter->prdeeprom) | ||
83 | kfree(adapter->prdeeprom); | ||
84 | LEAVE(); | ||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | mdelay(10); | ||
89 | |||
90 | ptr = (char *)adapter->prdeeprom; | ||
91 | |||
92 | /* skip the command header, but include the "value" u32 variable */ | ||
93 | ptr = ptr + sizeof(struct wlan_ioctl_regrdwr) - 4; | ||
94 | |||
95 | /* | ||
96 | * Return the result back to the user | ||
97 | */ | ||
98 | memcpy(bytes, ptr, eeprom->len); | ||
99 | |||
100 | if (adapter->prdeeprom) | ||
101 | kfree(adapter->prdeeprom); | ||
102 | // mutex_unlock(&priv->mutex); | ||
103 | |||
104 | return 0; | ||
105 | } | ||
106 | |||
107 | static void libertas_ethtool_get_stats(struct net_device * dev, | ||
108 | struct ethtool_stats * stats, u64 * data) | ||
109 | { | ||
110 | wlan_private *priv = dev->priv; | ||
111 | |||
112 | ENTER(); | ||
113 | |||
114 | stats->cmd = ETHTOOL_GSTATS; | ||
115 | BUG_ON(stats->n_stats != MESH_STATS_NUM); | ||
116 | |||
117 | data[0] = priv->mstats.fwd_drop_rbt; | ||
118 | data[1] = priv->mstats.fwd_drop_ttl; | ||
119 | data[2] = priv->mstats.fwd_drop_noroute; | ||
120 | data[3] = priv->mstats.fwd_drop_nobuf; | ||
121 | data[4] = priv->mstats.fwd_unicast_cnt; | ||
122 | data[5] = priv->mstats.fwd_bcast_cnt; | ||
123 | data[6] = priv->mstats.drop_blind; | ||
124 | |||
125 | LEAVE(); | ||
126 | } | ||
127 | |||
128 | static int libertas_ethtool_get_stats_count(struct net_device * dev) | ||
129 | { | ||
130 | int ret; | ||
131 | wlan_private *priv = dev->priv; | ||
132 | struct cmd_ds_mesh_access mesh_access; | ||
133 | |||
134 | ENTER(); | ||
135 | /* Get Mesh Statistics */ | ||
136 | ret = libertas_prepare_and_send_command(priv, | ||
137 | cmd_mesh_access, cmd_act_mesh_get_stats, | ||
138 | cmd_option_waitforrsp, 0, &mesh_access); | ||
139 | |||
140 | if (ret) { | ||
141 | LEAVE(); | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | priv->mstats.fwd_drop_rbt = mesh_access.data[0]; | ||
146 | priv->mstats.fwd_drop_ttl = mesh_access.data[1]; | ||
147 | priv->mstats.fwd_drop_noroute = mesh_access.data[2]; | ||
148 | priv->mstats.fwd_drop_nobuf = mesh_access.data[3]; | ||
149 | priv->mstats.fwd_unicast_cnt = mesh_access.data[4]; | ||
150 | priv->mstats.fwd_bcast_cnt = mesh_access.data[5]; | ||
151 | priv->mstats.drop_blind = mesh_access.data[6]; | ||
152 | |||
153 | LEAVE(); | ||
154 | return MESH_STATS_NUM; | ||
155 | } | ||
156 | |||
157 | static void libertas_ethtool_get_strings (struct net_device * dev, | ||
158 | u32 stringset, | ||
159 | u8 * s) | ||
160 | { | ||
161 | int i; | ||
162 | |||
163 | ENTER(); | ||
164 | switch (stringset) { | ||
165 | case ETH_SS_STATS: | ||
166 | for (i=0; i < MESH_STATS_NUM; i++) { | ||
167 | memcpy(s + i * ETH_GSTRING_LEN, | ||
168 | mesh_stat_strings[i], | ||
169 | ETH_GSTRING_LEN); | ||
170 | } | ||
171 | break; | ||
172 | } | ||
173 | LEAVE(); | ||
174 | } | ||
175 | |||
176 | struct ethtool_ops libertas_ethtool_ops = { | ||
177 | .get_drvinfo = libertas_ethtool_get_drvinfo, | ||
178 | .get_eeprom = libertas_ethtool_get_eeprom, | ||
179 | .get_eeprom_len = libertas_ethtool_get_eeprom_len, | ||
180 | .get_stats_count = libertas_ethtool_get_stats_count, | ||
181 | .get_ethtool_stats = libertas_ethtool_get_stats, | ||
182 | .get_strings = libertas_ethtool_get_strings, | ||
183 | }; | ||
184 | |||
diff --git a/drivers/net/wireless/libertas/fw.c b/drivers/net/wireless/libertas/fw.c new file mode 100644 index 000000000000..b194a4570791 --- /dev/null +++ b/drivers/net/wireless/libertas/fw.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /** | ||
2 | * This file contains the initialization for FW and HW | ||
3 | */ | ||
4 | #include <linux/module.h> | ||
5 | #include <linux/moduleparam.h> | ||
6 | |||
7 | #include <linux/vmalloc.h> | ||
8 | #include <linux/firmware.h> | ||
9 | #include <linux/version.h> | ||
10 | |||
11 | #include "host.h" | ||
12 | #include "sbi.h" | ||
13 | #include "defs.h" | ||
14 | #include "decl.h" | ||
15 | #include "dev.h" | ||
16 | #include "fw.h" | ||
17 | #include "wext.h" | ||
18 | #include "if_usb.h" | ||
19 | |||
20 | char *libertas_fw_name = NULL; | ||
21 | module_param_named(fw_name, libertas_fw_name, charp, 0644); | ||
22 | |||
23 | unsigned int libertas_debug = 0; | ||
24 | module_param(libertas_debug, int, 0); | ||
25 | |||
26 | /** | ||
27 | * @brief This function checks the validity of Boot2/FW image. | ||
28 | * | ||
29 | * @param data pointer to image | ||
30 | * len image length | ||
31 | * @return 0 or -1 | ||
32 | */ | ||
33 | static int check_fwfile_format(u8 *data, u32 totlen) | ||
34 | { | ||
35 | u8 bincmd, exit; | ||
36 | u32 blksize, offset, len; | ||
37 | int ret; | ||
38 | |||
39 | ret = 1; | ||
40 | exit = len = 0; | ||
41 | |||
42 | do { | ||
43 | bincmd = *data; | ||
44 | blksize = *(u32*)(data + offsetof(struct fwheader, datalength)); | ||
45 | switch (bincmd) { | ||
46 | case FW_HAS_DATA_TO_RECV: | ||
47 | offset = sizeof(struct fwheader) + blksize; | ||
48 | data += offset; | ||
49 | len += offset; | ||
50 | if (len >= totlen) | ||
51 | exit = 1; | ||
52 | break; | ||
53 | case FW_HAS_LAST_BLOCK: | ||
54 | exit = 1; | ||
55 | ret = 0; | ||
56 | break; | ||
57 | default: | ||
58 | exit = 1; | ||
59 | break; | ||
60 | } | ||
61 | } while (!exit); | ||
62 | |||
63 | if (ret) | ||
64 | lbs_pr_err("bin file format check FAIL...\n"); | ||
65 | else | ||
66 | lbs_pr_debug(1, "bin file format check PASS...\n"); | ||
67 | |||
68 | return ret; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * @brief This function downloads firmware image, gets | ||
73 | * HW spec from firmware and set basic parameters to | ||
74 | * firmware. | ||
75 | * | ||
76 | * @param priv A pointer to wlan_private structure | ||
77 | * @return 0 or -1 | ||
78 | */ | ||
79 | static int wlan_setup_station_hw(wlan_private * priv) | ||
80 | { | ||
81 | int ret = -1; | ||
82 | wlan_adapter *adapter = priv->adapter; | ||
83 | |||
84 | ENTER(); | ||
85 | |||
86 | if ((ret = request_firmware(&priv->firmware, libertas_fw_name, | ||
87 | priv->hotplug_device)) < 0) { | ||
88 | lbs_pr_err("request_firmware() failed, error code = %#x\n", | ||
89 | ret); | ||
90 | lbs_pr_err("%s not found in /lib/firmware\n", libertas_fw_name); | ||
91 | goto done; | ||
92 | } | ||
93 | |||
94 | if(check_fwfile_format(priv->firmware->data, priv->firmware->size)) { | ||
95 | release_firmware(priv->firmware); | ||
96 | goto done; | ||
97 | } | ||
98 | |||
99 | ret = libertas_sbi_prog_firmware(priv); | ||
100 | |||
101 | release_firmware(priv->firmware); | ||
102 | |||
103 | if (ret) { | ||
104 | lbs_pr_debug(1, "Bootloader in invalid state!\n"); | ||
105 | ret = -1; | ||
106 | goto done; | ||
107 | } | ||
108 | |||
109 | /* | ||
110 | * Read MAC address from HW | ||
111 | */ | ||
112 | memset(adapter->current_addr, 0xff, ETH_ALEN); | ||
113 | |||
114 | ret = libertas_prepare_and_send_command(priv, cmd_get_hw_spec, | ||
115 | 0, cmd_option_waitforrsp, 0, NULL); | ||
116 | |||
117 | if (ret) { | ||
118 | ret = -1; | ||
119 | goto done; | ||
120 | } | ||
121 | |||
122 | libertas_set_mac_packet_filter(priv); | ||
123 | |||
124 | /* Get the supported Data rates */ | ||
125 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, | ||
126 | cmd_act_get_tx_rate, | ||
127 | cmd_option_waitforrsp, 0, NULL); | ||
128 | |||
129 | if (ret) { | ||
130 | ret = -1; | ||
131 | goto done; | ||
132 | } | ||
133 | |||
134 | ret = 0; | ||
135 | done: | ||
136 | LEAVE(); | ||
137 | |||
138 | return (ret); | ||
139 | } | ||
140 | |||
141 | static int wlan_allocate_adapter(wlan_private * priv) | ||
142 | { | ||
143 | u32 ulbufsize; | ||
144 | wlan_adapter *adapter = priv->adapter; | ||
145 | |||
146 | struct bss_descriptor *ptempscantable; | ||
147 | |||
148 | /* Allocate buffer to store the BSSID list */ | ||
149 | ulbufsize = sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST; | ||
150 | if (!(ptempscantable = kmalloc(ulbufsize, GFP_KERNEL))) { | ||
151 | libertas_free_adapter(priv); | ||
152 | return -1; | ||
153 | } | ||
154 | |||
155 | adapter->scantable = ptempscantable; | ||
156 | memset(adapter->scantable, 0, ulbufsize); | ||
157 | |||
158 | /* Allocate the command buffers */ | ||
159 | libertas_allocate_cmd_buffer(priv); | ||
160 | |||
161 | memset(&adapter->libertas_ps_confirm_sleep, 0, sizeof(struct PS_CMD_ConfirmSleep)); | ||
162 | adapter->libertas_ps_confirm_sleep.seqnum = cpu_to_le16(++adapter->seqnum); | ||
163 | adapter->libertas_ps_confirm_sleep.command = | ||
164 | cpu_to_le16(cmd_802_11_ps_mode); | ||
165 | adapter->libertas_ps_confirm_sleep.size = | ||
166 | cpu_to_le16(sizeof(struct PS_CMD_ConfirmSleep)); | ||
167 | adapter->libertas_ps_confirm_sleep.result = 0; | ||
168 | adapter->libertas_ps_confirm_sleep.action = | ||
169 | cpu_to_le16(cmd_subcmd_sleep_confirmed); | ||
170 | |||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static void wlan_init_adapter(wlan_private * priv) | ||
175 | { | ||
176 | wlan_adapter *adapter = priv->adapter; | ||
177 | int i; | ||
178 | |||
179 | adapter->scanprobes = 0; | ||
180 | |||
181 | adapter->bcn_avg_factor = DEFAULT_BCN_AVG_FACTOR; | ||
182 | adapter->data_avg_factor = DEFAULT_DATA_AVG_FACTOR; | ||
183 | |||
184 | /* ATIM params */ | ||
185 | adapter->atimwindow = 0; | ||
186 | |||
187 | adapter->connect_status = libertas_disconnected; | ||
188 | memset(adapter->current_addr, 0xff, ETH_ALEN); | ||
189 | |||
190 | /* scan type */ | ||
191 | adapter->scantype = cmd_scan_type_active; | ||
192 | |||
193 | /* scan mode */ | ||
194 | adapter->scanmode = cmd_bss_type_any; | ||
195 | |||
196 | /* 802.11 specific */ | ||
197 | adapter->secinfo.WEPstatus = wlan802_11WEPdisabled; | ||
198 | for (i = 0; i < sizeof(adapter->wep_keys) / sizeof(adapter->wep_keys[0]); | ||
199 | i++) | ||
200 | memset(&adapter->wep_keys[i], 0, sizeof(struct WLAN_802_11_KEY)); | ||
201 | adapter->wep_tx_keyidx = 0; | ||
202 | adapter->secinfo.WEPstatus = wlan802_11WEPdisabled; | ||
203 | adapter->secinfo.authmode = wlan802_11authmodeopen; | ||
204 | adapter->secinfo.auth1xalg = WLAN_1X_AUTH_ALG_NONE; | ||
205 | adapter->secinfo.Encryptionmode = CIPHER_NONE; | ||
206 | adapter->inframode = wlan802_11infrastructure; | ||
207 | |||
208 | adapter->assoc_req = NULL; | ||
209 | |||
210 | adapter->numinscantable = 0; | ||
211 | adapter->pattemptedbssdesc = NULL; | ||
212 | mutex_init(&adapter->lock); | ||
213 | |||
214 | adapter->prescan = 1; | ||
215 | |||
216 | memset(&adapter->curbssparams, 0, sizeof(adapter->curbssparams)); | ||
217 | |||
218 | /* PnP and power profile */ | ||
219 | adapter->surpriseremoved = 0; | ||
220 | |||
221 | adapter->currentpacketfilter = | ||
222 | cmd_act_mac_rx_on | cmd_act_mac_tx_on; | ||
223 | |||
224 | adapter->radioon = RADIO_ON; | ||
225 | adapter->txantenna = RF_ANTENNA_2; | ||
226 | adapter->rxantenna = RF_ANTENNA_AUTO; | ||
227 | |||
228 | adapter->is_datarate_auto = 1; | ||
229 | adapter->beaconperiod = MRVDRV_BEACON_INTERVAL; | ||
230 | |||
231 | // set default value of capinfo. | ||
232 | #define SHORT_PREAMBLE_ALLOWED 1 | ||
233 | memset(&adapter->capinfo, 0, sizeof(adapter->capinfo)); | ||
234 | adapter->capinfo.shortpreamble = SHORT_PREAMBLE_ALLOWED; | ||
235 | |||
236 | adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL; | ||
237 | |||
238 | adapter->psmode = wlan802_11powermodecam; | ||
239 | adapter->multipledtim = MRVDRV_DEFAULT_MULTIPLE_DTIM; | ||
240 | |||
241 | adapter->listeninterval = MRVDRV_DEFAULT_LISTEN_INTERVAL; | ||
242 | |||
243 | adapter->psstate = PS_STATE_FULL_POWER; | ||
244 | adapter->needtowakeup = 0; | ||
245 | adapter->locallisteninterval = 0; /* default value in firmware will be used */ | ||
246 | |||
247 | adapter->datarate = 0; // Initially indicate the rate as auto | ||
248 | |||
249 | adapter->adhoc_grate_enabled = 0; | ||
250 | |||
251 | adapter->intcounter = 0; | ||
252 | |||
253 | adapter->currenttxskb = NULL; | ||
254 | adapter->pkttxctrl = 0; | ||
255 | |||
256 | memset(&adapter->tx_queue_ps, 0, NR_TX_QUEUE*sizeof(struct sk_buff*)); | ||
257 | adapter->tx_queue_idx = 0; | ||
258 | spin_lock_init(&adapter->txqueue_lock); | ||
259 | |||
260 | return; | ||
261 | } | ||
262 | |||
263 | static void command_timer_fn(unsigned long data); | ||
264 | |||
265 | int libertas_init_fw(wlan_private * priv) | ||
266 | { | ||
267 | int ret = -1; | ||
268 | wlan_adapter *adapter = priv->adapter; | ||
269 | |||
270 | ENTER(); | ||
271 | |||
272 | /* Allocate adapter structure */ | ||
273 | if ((ret = wlan_allocate_adapter(priv)) != 0) | ||
274 | goto done; | ||
275 | |||
276 | /* init adapter structure */ | ||
277 | wlan_init_adapter(priv); | ||
278 | |||
279 | /* init timer etc. */ | ||
280 | setup_timer(&adapter->command_timer, command_timer_fn, | ||
281 | (unsigned long)priv); | ||
282 | |||
283 | /* download fimrware etc. */ | ||
284 | if ((ret = wlan_setup_station_hw(priv)) != 0) { | ||
285 | del_timer_sync(&adapter->command_timer); | ||
286 | goto done; | ||
287 | } | ||
288 | |||
289 | /* init 802.11d */ | ||
290 | libertas_init_11d(priv); | ||
291 | |||
292 | ret = 0; | ||
293 | done: | ||
294 | LEAVE(); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | void libertas_free_adapter(wlan_private * priv) | ||
299 | { | ||
300 | wlan_adapter *adapter = priv->adapter; | ||
301 | |||
302 | if (!adapter) { | ||
303 | lbs_pr_debug(1, "Why double free adapter?:)\n"); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | lbs_pr_debug(1, "Free command buffer\n"); | ||
308 | libertas_free_cmd_buffer(priv); | ||
309 | |||
310 | lbs_pr_debug(1, "Free commandTimer\n"); | ||
311 | del_timer(&adapter->command_timer); | ||
312 | |||
313 | lbs_pr_debug(1, "Free scantable\n"); | ||
314 | if (adapter->scantable) { | ||
315 | kfree(adapter->scantable); | ||
316 | adapter->scantable = NULL; | ||
317 | } | ||
318 | |||
319 | lbs_pr_debug(1, "Free adapter\n"); | ||
320 | |||
321 | /* Free the adapter object itself */ | ||
322 | kfree(adapter); | ||
323 | priv->adapter = NULL; | ||
324 | } | ||
325 | |||
326 | /** | ||
327 | * This function handles the timeout of command sending. | ||
328 | * It will re-send the same command again. | ||
329 | */ | ||
330 | static void command_timer_fn(unsigned long data) | ||
331 | { | ||
332 | wlan_private *priv = (wlan_private *)data; | ||
333 | wlan_adapter *adapter = priv->adapter; | ||
334 | struct cmd_ctrl_node *ptempnode; | ||
335 | struct cmd_ds_command *cmd; | ||
336 | unsigned long flags; | ||
337 | |||
338 | ptempnode = adapter->cur_cmd; | ||
339 | cmd = (struct cmd_ds_command *)ptempnode->bufvirtualaddr; | ||
340 | |||
341 | lbs_pr_info("command_timer_fn fired (%x)\n", cmd->command); | ||
342 | |||
343 | if (!adapter->fw_ready) | ||
344 | return; | ||
345 | |||
346 | if (ptempnode == NULL) { | ||
347 | lbs_pr_debug(1, "PTempnode Empty\n"); | ||
348 | return; | ||
349 | } | ||
350 | |||
351 | spin_lock_irqsave(&adapter->driver_lock, flags); | ||
352 | adapter->cur_cmd = NULL; | ||
353 | spin_unlock_irqrestore(&adapter->driver_lock, flags); | ||
354 | |||
355 | lbs_pr_debug(1, "Re-sending same command as it timeout...!\n"); | ||
356 | libertas_queue_cmd(adapter, ptempnode, 0); | ||
357 | |||
358 | wake_up_interruptible(&priv->mainthread.waitq); | ||
359 | |||
360 | return; | ||
361 | } | ||
diff --git a/drivers/net/wireless/libertas/fw.h b/drivers/net/wireless/libertas/fw.h new file mode 100644 index 000000000000..1f9ae267a9e0 --- /dev/null +++ b/drivers/net/wireless/libertas/fw.h | |||
@@ -0,0 +1,13 @@ | |||
1 | /** | ||
2 | * This header file contains FW interface related definitions. | ||
3 | */ | ||
4 | #ifndef _WLAN_FW_H_ | ||
5 | #define _WLAN_FW_H_ | ||
6 | |||
7 | #ifndef DEV_NAME_LEN | ||
8 | #define DEV_NAME_LEN 32 | ||
9 | #endif | ||
10 | |||
11 | int libertas_init_fw(wlan_private * priv); | ||
12 | |||
13 | #endif /* _WLAN_FW_H_ */ | ||
diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h new file mode 100644 index 000000000000..c0faaecaf5be --- /dev/null +++ b/drivers/net/wireless/libertas/host.h | |||
@@ -0,0 +1,338 @@ | |||
1 | /** | ||
2 | * This file contains definitions of WLAN commands. | ||
3 | */ | ||
4 | |||
5 | #ifndef _HOST_H_ | ||
6 | #define _HOST_H_ | ||
7 | |||
8 | /** PUBLIC DEFINITIONS */ | ||
9 | #define DEFAULT_AD_HOC_CHANNEL 6 | ||
10 | #define DEFAULT_AD_HOC_CHANNEL_A 36 | ||
11 | |||
12 | /** IEEE 802.11 oids */ | ||
13 | #define OID_802_11_SSID 0x00008002 | ||
14 | #define OID_802_11_INFRASTRUCTURE_MODE 0x00008008 | ||
15 | #define OID_802_11_FRAGMENTATION_THRESHOLD 0x00008009 | ||
16 | #define OID_802_11_RTS_THRESHOLD 0x0000800A | ||
17 | #define OID_802_11_TX_ANTENNA_SELECTED 0x0000800D | ||
18 | #define OID_802_11_SUPPORTED_RATES 0x0000800E | ||
19 | #define OID_802_11_STATISTICS 0x00008012 | ||
20 | #define OID_802_11_TX_RETRYCOUNT 0x0000801D | ||
21 | #define OID_802_11D_ENABLE 0x00008020 | ||
22 | |||
23 | #define cmd_option_waitforrsp 0x0002 | ||
24 | |||
25 | /** Host command ID */ | ||
26 | #define cmd_code_dnld 0x0002 | ||
27 | #define cmd_get_hw_spec 0x0003 | ||
28 | #define cmd_eeprom_update 0x0004 | ||
29 | #define cmd_802_11_reset 0x0005 | ||
30 | #define cmd_802_11_scan 0x0006 | ||
31 | #define cmd_802_11_get_log 0x000b | ||
32 | #define cmd_mac_multicast_adr 0x0010 | ||
33 | #define cmd_802_11_authenticate 0x0011 | ||
34 | #define cmd_802_11_eeprom_access 0x0059 | ||
35 | #define cmd_802_11_associate 0x0050 | ||
36 | #define cmd_802_11_set_wep 0x0013 | ||
37 | #define cmd_802_11_get_stat 0x0014 | ||
38 | #define cmd_802_3_get_stat 0x0015 | ||
39 | #define cmd_802_11_snmp_mib 0x0016 | ||
40 | #define cmd_mac_reg_map 0x0017 | ||
41 | #define cmd_bbp_reg_map 0x0018 | ||
42 | #define cmd_mac_reg_access 0x0019 | ||
43 | #define cmd_bbp_reg_access 0x001a | ||
44 | #define cmd_rf_reg_access 0x001b | ||
45 | #define cmd_802_11_radio_control 0x001c | ||
46 | #define cmd_802_11_rf_channel 0x001d | ||
47 | #define cmd_802_11_rf_tx_power 0x001e | ||
48 | #define cmd_802_11_rssi 0x001f | ||
49 | #define cmd_802_11_rf_antenna 0x0020 | ||
50 | |||
51 | #define cmd_802_11_ps_mode 0x0021 | ||
52 | |||
53 | #define cmd_802_11_data_rate 0x0022 | ||
54 | #define cmd_rf_reg_map 0x0023 | ||
55 | #define cmd_802_11_deauthenticate 0x0024 | ||
56 | #define cmd_802_11_reassociate 0x0025 | ||
57 | #define cmd_802_11_disassociate 0x0026 | ||
58 | #define cmd_mac_control 0x0028 | ||
59 | #define cmd_802_11_ad_hoc_start 0x002b | ||
60 | #define cmd_802_11_ad_hoc_join 0x002c | ||
61 | |||
62 | #define cmd_802_11_query_tkip_reply_cntrs 0x002e | ||
63 | #define cmd_802_11_enable_rsn 0x002f | ||
64 | #define cmd_802_11_pairwise_tsc 0x0036 | ||
65 | #define cmd_802_11_group_tsc 0x0037 | ||
66 | #define cmd_802_11_key_material 0x005e | ||
67 | |||
68 | #define cmd_802_11_set_afc 0x003c | ||
69 | #define cmd_802_11_get_afc 0x003d | ||
70 | |||
71 | #define cmd_802_11_ad_hoc_stop 0x0040 | ||
72 | |||
73 | #define cmd_802_11_beacon_stop 0x0049 | ||
74 | |||
75 | #define cmd_802_11_mac_address 0x004D | ||
76 | #define cmd_802_11_eeprom_access 0x0059 | ||
77 | |||
78 | #define cmd_802_11_band_config 0x0058 | ||
79 | |||
80 | #define cmd_802_11d_domain_info 0x005b | ||
81 | |||
82 | #define cmd_802_11_sleep_params 0x0066 | ||
83 | |||
84 | #define cmd_802_11_inactivity_timeout 0x0067 | ||
85 | |||
86 | #define cmd_802_11_tpc_cfg 0x0072 | ||
87 | #define cmd_802_11_pwr_cfg 0x0073 | ||
88 | |||
89 | #define cmd_802_11_led_gpio_ctrl 0x004e | ||
90 | |||
91 | #define cmd_802_11_subscribe_event 0x0075 | ||
92 | |||
93 | #define cmd_802_11_rate_adapt_rateset 0x0076 | ||
94 | |||
95 | #define cmd_802_11_tx_rate_query 0x007f | ||
96 | |||
97 | #define cmd_get_tsf 0x0080 | ||
98 | |||
99 | #define cmd_bt_access 0x0087 | ||
100 | #define cmd_ret_bt_access 0x8087 | ||
101 | |||
102 | #define cmd_fwt_access 0x0088 | ||
103 | #define cmd_ret_fwt_access 0x8088 | ||
104 | |||
105 | #define cmd_mesh_access 0x0090 | ||
106 | #define cmd_ret_mesh_access 0x8090 | ||
107 | |||
108 | /* For the IEEE Power Save */ | ||
109 | #define cmd_subcmd_enter_ps 0x0030 | ||
110 | #define cmd_subcmd_exit_ps 0x0031 | ||
111 | #define cmd_subcmd_sleep_confirmed 0x0034 | ||
112 | #define cmd_subcmd_full_powerdown 0x0035 | ||
113 | #define cmd_subcmd_full_powerup 0x0036 | ||
114 | |||
115 | /* command RET code, MSB is set to 1 */ | ||
116 | #define cmd_ret_hw_spec_info 0x8003 | ||
117 | #define cmd_ret_eeprom_update 0x8004 | ||
118 | #define cmd_ret_802_11_reset 0x8005 | ||
119 | #define cmd_ret_802_11_scan 0x8006 | ||
120 | #define cmd_ret_802_11_get_log 0x800b | ||
121 | #define cmd_ret_mac_control 0x8028 | ||
122 | #define cmd_ret_mac_multicast_adr 0x8010 | ||
123 | #define cmd_ret_802_11_authenticate 0x8011 | ||
124 | #define cmd_ret_802_11_deauthenticate 0x8024 | ||
125 | #define cmd_ret_802_11_associate 0x8012 | ||
126 | #define cmd_ret_802_11_reassociate 0x8025 | ||
127 | #define cmd_ret_802_11_disassociate 0x8026 | ||
128 | #define cmd_ret_802_11_set_wep 0x8013 | ||
129 | #define cmd_ret_802_11_stat 0x8014 | ||
130 | #define cmd_ret_802_3_stat 0x8015 | ||
131 | #define cmd_ret_802_11_snmp_mib 0x8016 | ||
132 | #define cmd_ret_mac_reg_map 0x8017 | ||
133 | #define cmd_ret_bbp_reg_map 0x8018 | ||
134 | #define cmd_ret_rf_reg_map 0x8023 | ||
135 | #define cmd_ret_mac_reg_access 0x8019 | ||
136 | #define cmd_ret_bbp_reg_access 0x801a | ||
137 | #define cmd_ret_rf_reg_access 0x801b | ||
138 | #define cmd_ret_802_11_radio_control 0x801c | ||
139 | #define cmd_ret_802_11_rf_channel 0x801d | ||
140 | #define cmd_ret_802_11_rssi 0x801f | ||
141 | #define cmd_ret_802_11_rf_tx_power 0x801e | ||
142 | #define cmd_ret_802_11_rf_antenna 0x8020 | ||
143 | #define cmd_ret_802_11_ps_mode 0x8021 | ||
144 | #define cmd_ret_802_11_data_rate 0x8022 | ||
145 | |||
146 | #define cmd_ret_802_11_ad_hoc_start 0x802B | ||
147 | #define cmd_ret_802_11_ad_hoc_join 0x802C | ||
148 | |||
149 | #define cmd_ret_802_11_query_tkip_reply_cntrs 0x802e | ||
150 | #define cmd_ret_802_11_enable_rsn 0x802f | ||
151 | #define cmd_ret_802_11_pairwise_tsc 0x8036 | ||
152 | #define cmd_ret_802_11_group_tsc 0x8037 | ||
153 | #define cmd_ret_802_11_key_material 0x805e | ||
154 | |||
155 | #define cmd_enable_rsn 0x0001 | ||
156 | #define cmd_disable_rsn 0x0000 | ||
157 | |||
158 | #define cmd_act_set 0x0001 | ||
159 | #define cmd_act_get 0x0000 | ||
160 | |||
161 | #define cmd_act_get_AES (cmd_act_get + 2) | ||
162 | #define cmd_act_set_AES (cmd_act_set + 2) | ||
163 | #define cmd_act_remove_aes (cmd_act_set + 3) | ||
164 | |||
165 | #define cmd_ret_802_11_set_afc 0x803c | ||
166 | #define cmd_ret_802_11_get_afc 0x803d | ||
167 | |||
168 | #define cmd_ret_802_11_ad_hoc_stop 0x8040 | ||
169 | |||
170 | #define cmd_ret_802_11_beacon_stop 0x8049 | ||
171 | |||
172 | #define cmd_ret_802_11_mac_address 0x804D | ||
173 | #define cmd_ret_802_11_eeprom_access 0x8059 | ||
174 | |||
175 | #define cmd_ret_802_11_band_config 0x8058 | ||
176 | |||
177 | #define cmd_ret_802_11_sleep_params 0x8066 | ||
178 | |||
179 | #define cmd_ret_802_11_inactivity_timeout 0x8067 | ||
180 | |||
181 | #define cmd_ret_802_11d_domain_info (0x8000 | \ | ||
182 | cmd_802_11d_domain_info) | ||
183 | |||
184 | #define cmd_ret_802_11_tpc_cfg (cmd_802_11_tpc_cfg | 0x8000) | ||
185 | #define cmd_ret_802_11_pwr_cfg (cmd_802_11_pwr_cfg | 0x8000) | ||
186 | |||
187 | #define cmd_ret_802_11_led_gpio_ctrl 0x804e | ||
188 | |||
189 | #define cmd_ret_802_11_subscribe_event (cmd_802_11_subscribe_event | 0x8000) | ||
190 | |||
191 | #define cmd_ret_802_11_rate_adapt_rateset (cmd_802_11_rate_adapt_rateset | 0x8000) | ||
192 | |||
193 | #define cmd_rte_802_11_tx_rate_query (cmd_802_11_tx_rate_query | 0x8000) | ||
194 | |||
195 | #define cmd_ret_get_tsf 0x8080 | ||
196 | |||
197 | /* Define action or option for cmd_802_11_set_wep */ | ||
198 | #define cmd_act_add 0x0002 | ||
199 | #define cmd_act_remove 0x0004 | ||
200 | #define cmd_act_use_default 0x0008 | ||
201 | |||
202 | #define cmd_type_wep_40_bit 0x0001 | ||
203 | #define cmd_type_wep_104_bit 0x0002 | ||
204 | |||
205 | #define cmd_NUM_OF_WEP_KEYS 4 | ||
206 | |||
207 | #define cmd_WEP_KEY_INDEX_MASK 0x3fff | ||
208 | |||
209 | /* Define action or option for cmd_802_11_reset */ | ||
210 | #define cmd_act_halt 0x0003 | ||
211 | |||
212 | /* Define action or option for cmd_802_11_scan */ | ||
213 | #define cmd_bss_type_bss 0x0001 | ||
214 | #define cmd_bss_type_ibss 0x0002 | ||
215 | #define cmd_bss_type_any 0x0003 | ||
216 | |||
217 | /* Define action or option for cmd_802_11_scan */ | ||
218 | #define cmd_scan_type_active 0x0000 | ||
219 | #define cmd_scan_type_passive 0x0001 | ||
220 | |||
221 | #define cmd_scan_radio_type_bg 0 | ||
222 | |||
223 | #define cmd_scan_probe_delay_time 0 | ||
224 | |||
225 | /* Define action or option for cmd_mac_control */ | ||
226 | #define cmd_act_mac_rx_on 0x0001 | ||
227 | #define cmd_act_mac_tx_on 0x0002 | ||
228 | #define cmd_act_mac_loopback_on 0x0004 | ||
229 | #define cmd_act_mac_wep_enable 0x0008 | ||
230 | #define cmd_act_mac_int_enable 0x0010 | ||
231 | #define cmd_act_mac_multicast_enable 0x0020 | ||
232 | #define cmd_act_mac_broadcast_enable 0x0040 | ||
233 | #define cmd_act_mac_promiscuous_enable 0x0080 | ||
234 | #define cmd_act_mac_all_multicast_enable 0x0100 | ||
235 | #define cmd_act_mac_strict_protection_enable 0x0400 | ||
236 | |||
237 | /* Define action or option for cmd_802_11_radio_control */ | ||
238 | #define cmd_type_auto_preamble 0x0001 | ||
239 | #define cmd_type_short_preamble 0x0002 | ||
240 | #define cmd_type_long_preamble 0x0003 | ||
241 | |||
242 | #define TURN_ON_RF 0x01 | ||
243 | #define RADIO_ON 0x01 | ||
244 | #define RADIO_OFF 0x00 | ||
245 | |||
246 | #define SET_AUTO_PREAMBLE 0x05 | ||
247 | #define SET_SHORT_PREAMBLE 0x03 | ||
248 | #define SET_LONG_PREAMBLE 0x01 | ||
249 | |||
250 | /* Define action or option for CMD_802_11_RF_CHANNEL */ | ||
251 | #define cmd_opt_802_11_rf_channel_get 0x00 | ||
252 | #define cmd_opt_802_11_rf_channel_set 0x01 | ||
253 | |||
254 | /* Define action or option for cmd_802_11_rf_tx_power */ | ||
255 | #define cmd_act_tx_power_opt_get 0x0000 | ||
256 | #define cmd_act_tx_power_opt_set_high 0x8007 | ||
257 | #define cmd_act_tx_power_opt_set_mid 0x8004 | ||
258 | #define cmd_act_tx_power_opt_set_low 0x8000 | ||
259 | |||
260 | #define cmd_act_tx_power_index_high 0x0007 | ||
261 | #define cmd_act_tx_power_index_mid 0x0004 | ||
262 | #define cmd_act_tx_power_index_low 0x0000 | ||
263 | |||
264 | /* Define action or option for cmd_802_11_data_rate */ | ||
265 | #define cmd_act_set_tx_auto 0x0000 | ||
266 | #define cmd_act_set_tx_fix_rate 0x0001 | ||
267 | #define cmd_act_get_tx_rate 0x0002 | ||
268 | |||
269 | #define cmd_act_set_rx 0x0001 | ||
270 | #define cmd_act_set_tx 0x0002 | ||
271 | #define cmd_act_set_both 0x0003 | ||
272 | #define cmd_act_get_rx 0x0004 | ||
273 | #define cmd_act_get_tx 0x0008 | ||
274 | #define cmd_act_get_both 0x000c | ||
275 | |||
276 | /* Define action or option for cmd_802_11_ps_mode */ | ||
277 | #define cmd_type_cam 0x0000 | ||
278 | #define cmd_type_max_psp 0x0001 | ||
279 | #define cmd_type_fast_psp 0x0002 | ||
280 | |||
281 | /* Define action or option for cmd_bt_access */ | ||
282 | enum cmd_bt_access_opts { | ||
283 | /* The bt commands start at 5 instead of 1 because the old dft commands | ||
284 | * are mapped to 1-4. These old commands are no longer maintained and | ||
285 | * should not be called. | ||
286 | */ | ||
287 | cmd_act_bt_access_add = 5, | ||
288 | cmd_act_bt_access_del, | ||
289 | cmd_act_bt_access_list, | ||
290 | cmd_act_bt_access_reset | ||
291 | }; | ||
292 | |||
293 | /* Define action or option for cmd_fwt_access */ | ||
294 | enum cmd_fwt_access_opts { | ||
295 | cmd_act_fwt_access_add = 1, | ||
296 | cmd_act_fwt_access_del, | ||
297 | cmd_act_fwt_access_lookup, | ||
298 | cmd_act_fwt_access_list, | ||
299 | cmd_act_fwt_access_list_route, | ||
300 | cmd_act_fwt_access_list_neighbor, | ||
301 | cmd_act_fwt_access_reset, | ||
302 | cmd_act_fwt_access_cleanup, | ||
303 | cmd_act_fwt_access_time, | ||
304 | }; | ||
305 | |||
306 | /* Define action or option for cmd_mesh_access */ | ||
307 | enum cmd_mesh_access_opts { | ||
308 | cmd_act_mesh_get_ttl = 1, | ||
309 | cmd_act_mesh_set_ttl, | ||
310 | cmd_act_mesh_get_stats, | ||
311 | cmd_act_mesh_get_mpp, | ||
312 | cmd_act_mesh_set_mpp, | ||
313 | }; | ||
314 | |||
315 | /** Card Event definition */ | ||
316 | #define MACREG_INT_CODE_TX_PPA_FREE 0x00000000 | ||
317 | #define MACREG_INT_CODE_TX_DMA_DONE 0x00000001 | ||
318 | #define MACREG_INT_CODE_LINK_LOSE_W_SCAN 0x00000002 | ||
319 | #define MACREG_INT_CODE_LINK_LOSE_NO_SCAN 0x00000003 | ||
320 | #define MACREG_INT_CODE_LINK_SENSED 0x00000004 | ||
321 | #define MACREG_INT_CODE_CMD_FINISHED 0x00000005 | ||
322 | #define MACREG_INT_CODE_MIB_CHANGED 0x00000006 | ||
323 | #define MACREG_INT_CODE_INIT_DONE 0x00000007 | ||
324 | #define MACREG_INT_CODE_DEAUTHENTICATED 0x00000008 | ||
325 | #define MACREG_INT_CODE_DISASSOCIATED 0x00000009 | ||
326 | #define MACREG_INT_CODE_PS_AWAKE 0x0000000a | ||
327 | #define MACREG_INT_CODE_PS_SLEEP 0x0000000b | ||
328 | #define MACREG_INT_CODE_MIC_ERR_MULTICAST 0x0000000d | ||
329 | #define MACREG_INT_CODE_MIC_ERR_UNICAST 0x0000000e | ||
330 | #define MACREG_INT_CODE_WM_AWAKE 0x0000000f | ||
331 | #define MACREG_INT_CODE_ADHOC_BCN_LOST 0x00000011 | ||
332 | #define MACREG_INT_CODE_RSSI_LOW 0x00000019 | ||
333 | #define MACREG_INT_CODE_SNR_LOW 0x0000001a | ||
334 | #define MACREG_INT_CODE_MAX_FAIL 0x0000001b | ||
335 | #define MACREG_INT_CODE_RSSI_HIGH 0x0000001c | ||
336 | #define MACREG_INT_CODE_SNR_HIGH 0x0000001d | ||
337 | |||
338 | #endif /* _HOST_H_ */ | ||
diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h new file mode 100644 index 000000000000..f239e5d2435b --- /dev/null +++ b/drivers/net/wireless/libertas/hostcmd.h | |||
@@ -0,0 +1,693 @@ | |||
1 | /* | ||
2 | * This file contains the function prototypes, data structure | ||
3 | * and defines for all the host/station commands | ||
4 | */ | ||
5 | #ifndef __HOSTCMD__H | ||
6 | #define __HOSTCMD__H | ||
7 | |||
8 | #include <linux/wireless.h> | ||
9 | #include "11d.h" | ||
10 | #include "types.h" | ||
11 | |||
12 | /* 802.11-related definitions */ | ||
13 | |||
14 | /* TxPD descriptor */ | ||
15 | struct txpd { | ||
16 | /* Current Tx packet status */ | ||
17 | u32 tx_status; | ||
18 | /* Tx control */ | ||
19 | u32 tx_control; | ||
20 | u32 tx_packet_location; | ||
21 | /* Tx packet length */ | ||
22 | u16 tx_packet_length; | ||
23 | /* First 2 byte of destination MAC address */ | ||
24 | u8 tx_dest_addr_high[2]; | ||
25 | /* Last 4 byte of destination MAC address */ | ||
26 | u8 tx_dest_addr_low[4]; | ||
27 | /* Pkt Priority */ | ||
28 | u8 priority; | ||
29 | /* Pkt Trasnit Power control */ | ||
30 | u8 powermgmt; | ||
31 | /* Amount of time the packet has been queued in the driver (units = 2ms) */ | ||
32 | u8 pktdelay_2ms; | ||
33 | /* reserved */ | ||
34 | u8 reserved1; | ||
35 | }; | ||
36 | |||
37 | /* RxPD Descriptor */ | ||
38 | struct rxpd { | ||
39 | /* Current Rx packet status */ | ||
40 | u16 status; | ||
41 | |||
42 | /* SNR */ | ||
43 | u8 snr; | ||
44 | |||
45 | /* Tx control */ | ||
46 | u8 rx_control; | ||
47 | |||
48 | /* Pkt length */ | ||
49 | u16 pkt_len; | ||
50 | |||
51 | /* Noise Floor */ | ||
52 | u8 nf; | ||
53 | |||
54 | /* Rx Packet Rate */ | ||
55 | u8 rx_rate; | ||
56 | |||
57 | /* Pkt addr */ | ||
58 | u32 pkt_ptr; | ||
59 | |||
60 | /* Next Rx RxPD addr */ | ||
61 | u32 next_rxpd_ptr; | ||
62 | |||
63 | /* Pkt Priority */ | ||
64 | u8 priority; | ||
65 | u8 reserved[3]; | ||
66 | }; | ||
67 | |||
68 | struct cmd_ctrl_node { | ||
69 | /* CMD link list */ | ||
70 | struct list_head list; | ||
71 | u32 status; | ||
72 | /* CMD ID */ | ||
73 | u32 cmd_oid; | ||
74 | /*CMD wait option: wait for finish or no wait */ | ||
75 | u16 wait_option; | ||
76 | /* command parameter */ | ||
77 | void *pdata_buf; | ||
78 | /*command data */ | ||
79 | u8 *bufvirtualaddr; | ||
80 | u16 cmdflags; | ||
81 | /* wait queue */ | ||
82 | u16 cmdwaitqwoken; | ||
83 | wait_queue_head_t cmdwait_q; | ||
84 | }; | ||
85 | |||
86 | /* WLAN_802_11_KEY | ||
87 | * | ||
88 | * Generic structure to hold all key types. key type (WEP40, WEP104, TKIP, AES) | ||
89 | * is determined from the keylength field. | ||
90 | */ | ||
91 | struct WLAN_802_11_KEY { | ||
92 | u32 len; | ||
93 | u32 flags; /* KEY_INFO_* from wlan_defs.h */ | ||
94 | u8 key[MRVL_MAX_KEY_WPA_KEY_LENGTH]; | ||
95 | u16 type; /* KEY_TYPE_* from wlan_defs.h */ | ||
96 | }; | ||
97 | |||
98 | struct IE_WPA { | ||
99 | u8 elementid; | ||
100 | u8 len; | ||
101 | u8 oui[4]; | ||
102 | u16 version; | ||
103 | }; | ||
104 | |||
105 | struct WLAN_802_11_SSID { | ||
106 | /* SSID length */ | ||
107 | u32 ssidlength; | ||
108 | |||
109 | /* SSID information field */ | ||
110 | u8 ssid[IW_ESSID_MAX_SIZE]; | ||
111 | }; | ||
112 | |||
113 | struct WPA_SUPPLICANT { | ||
114 | u8 wpa_ie[256]; | ||
115 | u8 wpa_ie_len; | ||
116 | }; | ||
117 | |||
118 | /* wlan_offset_value */ | ||
119 | struct wlan_offset_value { | ||
120 | u32 offset; | ||
121 | u32 value; | ||
122 | }; | ||
123 | |||
124 | struct WLAN_802_11_FIXED_IEs { | ||
125 | u8 timestamp[8]; | ||
126 | u16 beaconinterval; | ||
127 | u16 capabilities; | ||
128 | }; | ||
129 | |||
130 | struct WLAN_802_11_VARIABLE_IEs { | ||
131 | u8 elementid; | ||
132 | u8 length; | ||
133 | u8 data[1]; | ||
134 | }; | ||
135 | |||
136 | /* Define general data structure */ | ||
137 | /* cmd_DS_GEN */ | ||
138 | struct cmd_ds_gen { | ||
139 | u16 command; | ||
140 | u16 size; | ||
141 | u16 seqnum; | ||
142 | u16 result; | ||
143 | }; | ||
144 | |||
145 | #define S_DS_GEN sizeof(struct cmd_ds_gen) | ||
146 | /* | ||
147 | * Define data structure for cmd_get_hw_spec | ||
148 | * This structure defines the response for the GET_HW_SPEC command | ||
149 | */ | ||
150 | struct cmd_ds_get_hw_spec { | ||
151 | /* HW Interface version number */ | ||
152 | u16 hwifversion; | ||
153 | /* HW version number */ | ||
154 | u16 version; | ||
155 | /* Max number of TxPD FW can handle */ | ||
156 | u16 nr_txpd; | ||
157 | /* Max no of Multicast address */ | ||
158 | u16 nr_mcast_adr; | ||
159 | /* MAC address */ | ||
160 | u8 permanentaddr[6]; | ||
161 | |||
162 | /* region Code */ | ||
163 | u16 regioncode; | ||
164 | |||
165 | /* Number of antenna used */ | ||
166 | u16 nr_antenna; | ||
167 | |||
168 | /* FW release number, example 0x1234=1.2.3.4 */ | ||
169 | u32 fwreleasenumber; | ||
170 | |||
171 | /* Base Address of TxPD queue */ | ||
172 | u32 wcb_base; | ||
173 | /* Read Pointer of RxPd queue */ | ||
174 | u32 rxpd_rdptr; | ||
175 | |||
176 | /* Write Pointer of RxPd queue */ | ||
177 | u32 rxpd_wrptr; | ||
178 | |||
179 | /*FW/HW capability */ | ||
180 | u32 fwcapinfo; | ||
181 | } __attribute__ ((packed)); | ||
182 | |||
183 | struct cmd_ds_802_11_reset { | ||
184 | u16 action; | ||
185 | }; | ||
186 | |||
187 | struct cmd_ds_802_11_subscribe_event { | ||
188 | u16 action; | ||
189 | u16 events; | ||
190 | }; | ||
191 | |||
192 | /* | ||
193 | * This scan handle Country Information IE(802.11d compliant) | ||
194 | * Define data structure for cmd_802_11_scan | ||
195 | */ | ||
196 | struct cmd_ds_802_11_scan { | ||
197 | u8 bsstype; | ||
198 | u8 BSSID[ETH_ALEN]; | ||
199 | u8 tlvbuffer[1]; | ||
200 | #if 0 | ||
201 | mrvlietypes_ssidparamset_t ssidParamSet; | ||
202 | mrvlietypes_chanlistparamset_t ChanListParamSet; | ||
203 | mrvlietypes_ratesparamset_t OpRateSet; | ||
204 | #endif | ||
205 | }; | ||
206 | |||
207 | struct cmd_ds_802_11_scan_rsp { | ||
208 | u16 bssdescriptsize; | ||
209 | u8 nr_sets; | ||
210 | u8 bssdesc_and_tlvbuffer[1]; | ||
211 | }; | ||
212 | |||
213 | struct cmd_ds_802_11_get_log { | ||
214 | u32 mcasttxframe; | ||
215 | u32 failed; | ||
216 | u32 retry; | ||
217 | u32 multiretry; | ||
218 | u32 framedup; | ||
219 | u32 rtssuccess; | ||
220 | u32 rtsfailure; | ||
221 | u32 ackfailure; | ||
222 | u32 rxfrag; | ||
223 | u32 mcastrxframe; | ||
224 | u32 fcserror; | ||
225 | u32 txframe; | ||
226 | u32 wepundecryptable; | ||
227 | }; | ||
228 | |||
229 | struct cmd_ds_mac_control { | ||
230 | u16 action; | ||
231 | u16 reserved; | ||
232 | }; | ||
233 | |||
234 | struct cmd_ds_mac_multicast_adr { | ||
235 | u16 action; | ||
236 | u16 nr_of_adrs; | ||
237 | u8 maclist[ETH_ALEN * MRVDRV_MAX_MULTICAST_LIST_SIZE]; | ||
238 | }; | ||
239 | |||
240 | struct cmd_ds_802_11_authenticate { | ||
241 | u8 macaddr[ETH_ALEN]; | ||
242 | u8 authtype; | ||
243 | u8 reserved[10]; | ||
244 | }; | ||
245 | |||
246 | struct cmd_ds_802_11_deauthenticate { | ||
247 | u8 macaddr[6]; | ||
248 | u16 reasoncode; | ||
249 | }; | ||
250 | |||
251 | struct cmd_ds_802_11_associate { | ||
252 | u8 peerstaaddr[6]; | ||
253 | struct ieeetypes_capinfo capinfo; | ||
254 | u16 listeninterval; | ||
255 | u16 bcnperiod; | ||
256 | u8 dtimperiod; | ||
257 | |||
258 | #if 0 | ||
259 | mrvlietypes_ssidparamset_t ssidParamSet; | ||
260 | mrvlietypes_phyparamset_t phyparamset; | ||
261 | mrvlietypes_ssparamset_t ssparamset; | ||
262 | mrvlietypes_ratesparamset_t ratesParamSet; | ||
263 | #endif | ||
264 | } __attribute__ ((packed)); | ||
265 | |||
266 | struct cmd_ds_802_11_disassociate { | ||
267 | u8 destmacaddr[6]; | ||
268 | u16 reasoncode; | ||
269 | }; | ||
270 | |||
271 | struct cmd_ds_802_11_associate_rsp { | ||
272 | struct ieeetypes_assocrsp assocRsp; | ||
273 | }; | ||
274 | |||
275 | struct cmd_ds_802_11_ad_hoc_result { | ||
276 | u8 PAD[3]; | ||
277 | u8 BSSID[ETH_ALEN]; | ||
278 | }; | ||
279 | |||
280 | struct cmd_ds_802_11_set_wep { | ||
281 | /* ACT_ADD, ACT_REMOVE or ACT_ENABLE */ | ||
282 | u16 action; | ||
283 | |||
284 | /* key Index selected for Tx */ | ||
285 | u16 keyindex; | ||
286 | |||
287 | /* 40, 128bit or TXWEP */ | ||
288 | u8 keytype[4]; | ||
289 | u8 keymaterial[4][16]; | ||
290 | }; | ||
291 | |||
292 | struct cmd_ds_802_3_get_stat { | ||
293 | u32 xmitok; | ||
294 | u32 rcvok; | ||
295 | u32 xmiterror; | ||
296 | u32 rcverror; | ||
297 | u32 rcvnobuffer; | ||
298 | u32 rcvcrcerror; | ||
299 | }; | ||
300 | |||
301 | struct cmd_ds_802_11_get_stat { | ||
302 | u32 txfragmentcnt; | ||
303 | u32 mcasttxframecnt; | ||
304 | u32 failedcnt; | ||
305 | u32 retrycnt; | ||
306 | u32 Multipleretrycnt; | ||
307 | u32 rtssuccesscnt; | ||
308 | u32 rtsfailurecnt; | ||
309 | u32 ackfailurecnt; | ||
310 | u32 frameduplicatecnt; | ||
311 | u32 rxfragmentcnt; | ||
312 | u32 mcastrxframecnt; | ||
313 | u32 fcserrorcnt; | ||
314 | u32 bcasttxframecnt; | ||
315 | u32 bcastrxframecnt; | ||
316 | u32 txbeacon; | ||
317 | u32 rxbeacon; | ||
318 | u32 wepundecryptable; | ||
319 | }; | ||
320 | |||
321 | struct cmd_ds_802_11_snmp_mib { | ||
322 | u16 querytype; | ||
323 | u16 oid; | ||
324 | u16 bufsize; | ||
325 | u8 value[128]; | ||
326 | }; | ||
327 | |||
328 | struct cmd_ds_mac_reg_map { | ||
329 | u16 buffersize; | ||
330 | u8 regmap[128]; | ||
331 | u16 reserved; | ||
332 | }; | ||
333 | |||
334 | struct cmd_ds_bbp_reg_map { | ||
335 | u16 buffersize; | ||
336 | u8 regmap[128]; | ||
337 | u16 reserved; | ||
338 | }; | ||
339 | |||
340 | struct cmd_ds_rf_reg_map { | ||
341 | u16 buffersize; | ||
342 | u8 regmap[64]; | ||
343 | u16 reserved; | ||
344 | }; | ||
345 | |||
346 | struct cmd_ds_mac_reg_access { | ||
347 | u16 action; | ||
348 | u16 offset; | ||
349 | u32 value; | ||
350 | }; | ||
351 | |||
352 | struct cmd_ds_bbp_reg_access { | ||
353 | u16 action; | ||
354 | u16 offset; | ||
355 | u8 value; | ||
356 | u8 reserved[3]; | ||
357 | }; | ||
358 | |||
359 | struct cmd_ds_rf_reg_access { | ||
360 | u16 action; | ||
361 | u16 offset; | ||
362 | u8 value; | ||
363 | u8 reserved[3]; | ||
364 | }; | ||
365 | |||
366 | struct cmd_ds_802_11_radio_control { | ||
367 | u16 action; | ||
368 | u16 control; | ||
369 | }; | ||
370 | |||
371 | struct cmd_ds_802_11_sleep_params { | ||
372 | /* ACT_GET/ACT_SET */ | ||
373 | u16 action; | ||
374 | |||
375 | /* Sleep clock error in ppm */ | ||
376 | u16 error; | ||
377 | |||
378 | /* Wakeup offset in usec */ | ||
379 | u16 offset; | ||
380 | |||
381 | /* Clock stabilization time in usec */ | ||
382 | u16 stabletime; | ||
383 | |||
384 | /* control periodic calibration */ | ||
385 | u8 calcontrol; | ||
386 | |||
387 | /* control the use of external sleep clock */ | ||
388 | u8 externalsleepclk; | ||
389 | |||
390 | /* reserved field, should be set to zero */ | ||
391 | u16 reserved; | ||
392 | }; | ||
393 | |||
394 | struct cmd_ds_802_11_inactivity_timeout { | ||
395 | /* ACT_GET/ACT_SET */ | ||
396 | u16 action; | ||
397 | |||
398 | /* Inactivity timeout in msec */ | ||
399 | u16 timeout; | ||
400 | }; | ||
401 | |||
402 | struct cmd_ds_802_11_rf_channel { | ||
403 | u16 action; | ||
404 | u16 currentchannel; | ||
405 | u16 rftype; | ||
406 | u16 reserved; | ||
407 | u8 channellist[32]; | ||
408 | }; | ||
409 | |||
410 | struct cmd_ds_802_11_rssi { | ||
411 | /* weighting factor */ | ||
412 | u16 N; | ||
413 | |||
414 | u16 reserved_0; | ||
415 | u16 reserved_1; | ||
416 | u16 reserved_2; | ||
417 | }; | ||
418 | |||
419 | struct cmd_ds_802_11_rssi_rsp { | ||
420 | u16 SNR; | ||
421 | u16 noisefloor; | ||
422 | u16 avgSNR; | ||
423 | u16 avgnoisefloor; | ||
424 | }; | ||
425 | |||
426 | struct cmd_ds_802_11_mac_address { | ||
427 | u16 action; | ||
428 | u8 macadd[ETH_ALEN]; | ||
429 | }; | ||
430 | |||
431 | struct cmd_ds_802_11_rf_tx_power { | ||
432 | u16 action; | ||
433 | u16 currentlevel; | ||
434 | }; | ||
435 | |||
436 | struct cmd_ds_802_11_rf_antenna { | ||
437 | u16 action; | ||
438 | |||
439 | /* Number of antennas or 0xffff(diversity) */ | ||
440 | u16 antennamode; | ||
441 | |||
442 | }; | ||
443 | |||
444 | struct cmd_ds_802_11_ps_mode { | ||
445 | u16 action; | ||
446 | u16 nullpktinterval; | ||
447 | u16 multipledtim; | ||
448 | u16 reserved; | ||
449 | u16 locallisteninterval; | ||
450 | }; | ||
451 | |||
452 | struct PS_CMD_ConfirmSleep { | ||
453 | u16 command; | ||
454 | u16 size; | ||
455 | u16 seqnum; | ||
456 | u16 result; | ||
457 | |||
458 | u16 action; | ||
459 | u16 reserved1; | ||
460 | u16 multipledtim; | ||
461 | u16 reserved; | ||
462 | u16 locallisteninterval; | ||
463 | }; | ||
464 | |||
465 | struct cmd_ds_802_11_data_rate { | ||
466 | u16 action; | ||
467 | u16 reserverd; | ||
468 | u8 datarate[G_SUPPORTED_RATES]; | ||
469 | }; | ||
470 | |||
471 | struct cmd_ds_802_11_rate_adapt_rateset { | ||
472 | u16 action; | ||
473 | u16 enablehwauto; | ||
474 | u16 bitmap; | ||
475 | }; | ||
476 | |||
477 | struct cmd_ds_802_11_ad_hoc_start { | ||
478 | u8 SSID[IW_ESSID_MAX_SIZE]; | ||
479 | u8 bsstype; | ||
480 | u16 beaconperiod; | ||
481 | u8 dtimperiod; | ||
482 | union IEEEtypes_ssparamset ssparamset; | ||
483 | union ieeetypes_phyparamset phyparamset; | ||
484 | u16 probedelay; | ||
485 | struct ieeetypes_capinfo cap; | ||
486 | u8 datarate[G_SUPPORTED_RATES]; | ||
487 | u8 tlv_memory_size_pad[100]; | ||
488 | } __attribute__ ((packed)); | ||
489 | |||
490 | struct adhoc_bssdesc { | ||
491 | u8 BSSID[6]; | ||
492 | u8 SSID[32]; | ||
493 | u8 bsstype; | ||
494 | u16 beaconperiod; | ||
495 | u8 dtimperiod; | ||
496 | u8 timestamp[8]; | ||
497 | u8 localtime[8]; | ||
498 | union ieeetypes_phyparamset phyparamset; | ||
499 | union IEEEtypes_ssparamset ssparamset; | ||
500 | struct ieeetypes_capinfo cap; | ||
501 | u8 datarates[G_SUPPORTED_RATES]; | ||
502 | |||
503 | /* DO NOT ADD ANY FIELDS TO THIS STRUCTURE. It is used below in the | ||
504 | * Adhoc join command and will cause a binary layout mismatch with | ||
505 | * the firmware | ||
506 | */ | ||
507 | } __attribute__ ((packed)); | ||
508 | |||
509 | struct cmd_ds_802_11_ad_hoc_join { | ||
510 | struct adhoc_bssdesc bssdescriptor; | ||
511 | u16 failtimeout; | ||
512 | u16 probedelay; | ||
513 | |||
514 | } __attribute__ ((packed)); | ||
515 | |||
516 | struct cmd_ds_802_11_enable_rsn { | ||
517 | u16 action; | ||
518 | u16 enable; | ||
519 | }; | ||
520 | |||
521 | struct MrvlIEtype_keyParamSet { | ||
522 | /* type ID */ | ||
523 | u16 type; | ||
524 | |||
525 | /* length of Payload */ | ||
526 | u16 length; | ||
527 | |||
528 | /* type of key: WEP=0, TKIP=1, AES=2 */ | ||
529 | u16 keytypeid; | ||
530 | |||
531 | /* key control Info specific to a keytypeid */ | ||
532 | u16 keyinfo; | ||
533 | |||
534 | /* length of key */ | ||
535 | u16 keylen; | ||
536 | |||
537 | /* key material of size keylen */ | ||
538 | u8 key[32]; | ||
539 | }; | ||
540 | |||
541 | struct cmd_ds_802_11_key_material { | ||
542 | u16 action; | ||
543 | struct MrvlIEtype_keyParamSet keyParamSet[2]; | ||
544 | } __attribute__ ((packed)); | ||
545 | |||
546 | struct cmd_ds_802_11_eeprom_access { | ||
547 | u16 action; | ||
548 | |||
549 | /* multiple 4 */ | ||
550 | u16 offset; | ||
551 | u16 bytecount; | ||
552 | u8 value; | ||
553 | } __attribute__ ((packed)); | ||
554 | |||
555 | struct cmd_ds_802_11_tpc_cfg { | ||
556 | u16 action; | ||
557 | u8 enable; | ||
558 | s8 P0; | ||
559 | s8 P1; | ||
560 | s8 P2; | ||
561 | u8 usesnr; | ||
562 | } __attribute__ ((packed)); | ||
563 | |||
564 | struct cmd_ds_802_11_led_ctrl { | ||
565 | u16 action; | ||
566 | u16 numled; | ||
567 | u8 data[256]; | ||
568 | } __attribute__ ((packed)); | ||
569 | |||
570 | struct cmd_ds_802_11_pwr_cfg { | ||
571 | u16 action; | ||
572 | u8 enable; | ||
573 | s8 PA_P0; | ||
574 | s8 PA_P1; | ||
575 | s8 PA_P2; | ||
576 | } __attribute__ ((packed)); | ||
577 | |||
578 | struct cmd_ds_802_11_afc { | ||
579 | u16 afc_auto; | ||
580 | union { | ||
581 | struct { | ||
582 | u16 threshold; | ||
583 | u16 period; | ||
584 | }; | ||
585 | struct { | ||
586 | s16 timing_offset; | ||
587 | s16 carrier_offset; | ||
588 | }; | ||
589 | }; | ||
590 | } __attribute__ ((packed)); | ||
591 | |||
592 | struct cmd_tx_rate_query { | ||
593 | u16 txrate; | ||
594 | } __attribute__ ((packed)); | ||
595 | |||
596 | struct cmd_ds_get_tsf { | ||
597 | __le64 tsfvalue; | ||
598 | } __attribute__ ((packed)); | ||
599 | |||
600 | struct cmd_ds_bt_access { | ||
601 | u16 action; | ||
602 | u32 id; | ||
603 | u8 addr1[ETH_ALEN]; | ||
604 | u8 addr2[ETH_ALEN]; | ||
605 | } __attribute__ ((packed)); | ||
606 | |||
607 | struct cmd_ds_fwt_access { | ||
608 | u16 action; | ||
609 | u32 id; | ||
610 | u8 da[ETH_ALEN]; | ||
611 | u8 dir; | ||
612 | u8 ra[ETH_ALEN]; | ||
613 | u32 ssn; | ||
614 | u32 dsn; | ||
615 | u32 metric; | ||
616 | u8 hopcount; | ||
617 | u8 ttl; | ||
618 | u32 expiration; | ||
619 | u8 sleepmode; | ||
620 | u32 snr; | ||
621 | u32 references; | ||
622 | } __attribute__ ((packed)); | ||
623 | |||
624 | #define MESH_STATS_NUM 7 | ||
625 | struct cmd_ds_mesh_access { | ||
626 | u16 action; | ||
627 | u32 data[MESH_STATS_NUM + 1]; /* last position reserved */ | ||
628 | } __attribute__ ((packed)); | ||
629 | |||
630 | struct cmd_ds_command { | ||
631 | /* command header */ | ||
632 | u16 command; | ||
633 | u16 size; | ||
634 | u16 seqnum; | ||
635 | u16 result; | ||
636 | |||
637 | /* command Body */ | ||
638 | union { | ||
639 | struct cmd_ds_get_hw_spec hwspec; | ||
640 | struct cmd_ds_802_11_ps_mode psmode; | ||
641 | struct cmd_ds_802_11_scan scan; | ||
642 | struct cmd_ds_802_11_scan_rsp scanresp; | ||
643 | struct cmd_ds_mac_control macctrl; | ||
644 | struct cmd_ds_802_11_associate associate; | ||
645 | struct cmd_ds_802_11_deauthenticate deauth; | ||
646 | struct cmd_ds_802_11_set_wep wep; | ||
647 | struct cmd_ds_802_11_ad_hoc_start ads; | ||
648 | struct cmd_ds_802_11_reset reset; | ||
649 | struct cmd_ds_802_11_ad_hoc_result result; | ||
650 | struct cmd_ds_802_11_get_log glog; | ||
651 | struct cmd_ds_802_11_authenticate auth; | ||
652 | struct cmd_ds_802_11_get_stat gstat; | ||
653 | struct cmd_ds_802_3_get_stat gstat_8023; | ||
654 | struct cmd_ds_802_11_snmp_mib smib; | ||
655 | struct cmd_ds_802_11_rf_tx_power txp; | ||
656 | struct cmd_ds_802_11_rf_antenna rant; | ||
657 | struct cmd_ds_802_11_data_rate drate; | ||
658 | struct cmd_ds_802_11_rate_adapt_rateset rateset; | ||
659 | struct cmd_ds_mac_multicast_adr madr; | ||
660 | struct cmd_ds_802_11_ad_hoc_join adj; | ||
661 | struct cmd_ds_802_11_radio_control radio; | ||
662 | struct cmd_ds_802_11_rf_channel rfchannel; | ||
663 | struct cmd_ds_802_11_rssi rssi; | ||
664 | struct cmd_ds_802_11_rssi_rsp rssirsp; | ||
665 | struct cmd_ds_802_11_disassociate dassociate; | ||
666 | struct cmd_ds_802_11_mac_address macadd; | ||
667 | struct cmd_ds_802_11_enable_rsn enbrsn; | ||
668 | struct cmd_ds_802_11_key_material keymaterial; | ||
669 | struct cmd_ds_mac_reg_access macreg; | ||
670 | struct cmd_ds_bbp_reg_access bbpreg; | ||
671 | struct cmd_ds_rf_reg_access rfreg; | ||
672 | struct cmd_ds_802_11_eeprom_access rdeeprom; | ||
673 | |||
674 | struct cmd_ds_802_11d_domain_info domaininfo; | ||
675 | struct cmd_ds_802_11d_domain_info domaininforesp; | ||
676 | |||
677 | struct cmd_ds_802_11_sleep_params sleep_params; | ||
678 | struct cmd_ds_802_11_inactivity_timeout inactivity_timeout; | ||
679 | struct cmd_ds_802_11_tpc_cfg tpccfg; | ||
680 | struct cmd_ds_802_11_pwr_cfg pwrcfg; | ||
681 | struct cmd_ds_802_11_afc afc; | ||
682 | struct cmd_ds_802_11_led_ctrl ledgpio; | ||
683 | |||
684 | struct cmd_tx_rate_query txrate; | ||
685 | struct cmd_ds_bt_access bt; | ||
686 | struct cmd_ds_fwt_access fwt; | ||
687 | struct cmd_ds_mesh_access mesh; | ||
688 | struct cmd_ds_get_tsf gettsf; | ||
689 | struct cmd_ds_802_11_subscribe_event subscribe_event; | ||
690 | } params; | ||
691 | } __attribute__ ((packed)); | ||
692 | |||
693 | #endif | ||
diff --git a/drivers/net/wireless/libertas/if_bootcmd.c b/drivers/net/wireless/libertas/if_bootcmd.c new file mode 100644 index 000000000000..567000c3e87b --- /dev/null +++ b/drivers/net/wireless/libertas/if_bootcmd.c | |||
@@ -0,0 +1,38 @@ | |||
1 | /** | ||
2 | * This file contains functions used in USB Boot command | ||
3 | * and Boot2/FW update | ||
4 | */ | ||
5 | |||
6 | #include <linux/delay.h> | ||
7 | #include <linux/firmware.h> | ||
8 | #include <linux/netdevice.h> | ||
9 | #include <linux/usb.h> | ||
10 | |||
11 | #include "defs.h" | ||
12 | #include "dev.h" | ||
13 | #include "if_usb.h" | ||
14 | |||
15 | /** | ||
16 | * @brief This function issues Boot command to the Boot2 code | ||
17 | * @param ivalue 1:Boot from FW by USB-Download | ||
18 | * 2:Boot from FW in EEPROM | ||
19 | * @return 0 | ||
20 | */ | ||
21 | int if_usb_issue_boot_command(wlan_private *priv, int ivalue) | ||
22 | { | ||
23 | struct usb_card_rec *cardp = priv->wlan_dev.card; | ||
24 | struct bootcmdstr sbootcmd; | ||
25 | int i; | ||
26 | |||
27 | /* Prepare command */ | ||
28 | sbootcmd.u32magicnumber = BOOT_CMD_MAGIC_NUMBER; | ||
29 | sbootcmd.u8cmd_tag = ivalue; | ||
30 | for (i=0; i<11; i++) | ||
31 | sbootcmd.au8dumy[i]=0x00; | ||
32 | memcpy(cardp->bulk_out_buffer, &sbootcmd, sizeof(struct bootcmdstr)); | ||
33 | |||
34 | /* Issue command */ | ||
35 | usb_tx_block(priv, cardp->bulk_out_buffer, sizeof(struct bootcmdstr)); | ||
36 | |||
37 | return 0; | ||
38 | } | ||
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c new file mode 100644 index 000000000000..695fb6a66ffe --- /dev/null +++ b/drivers/net/wireless/libertas/if_usb.c | |||
@@ -0,0 +1,952 @@ | |||
1 | /** | ||
2 | * This file contains functions used in USB interface module. | ||
3 | */ | ||
4 | #include <linux/delay.h> | ||
5 | #include <linux/firmware.h> | ||
6 | #include <linux/netdevice.h> | ||
7 | #include <linux/usb.h> | ||
8 | |||
9 | #include "host.h" | ||
10 | #include "sbi.h" | ||
11 | #include "decl.h" | ||
12 | #include "defs.h" | ||
13 | #include "dev.h" | ||
14 | #include "if_usb.h" | ||
15 | |||
16 | #define MESSAGE_HEADER_LEN 4 | ||
17 | |||
18 | static const char usbdriver_name[] = "usb8xxx"; | ||
19 | |||
20 | static struct usb_device_id if_usb_table[] = { | ||
21 | /* Enter the device signature inside */ | ||
22 | { | ||
23 | USB_DEVICE(USB8388_VID_1, USB8388_PID_1), | ||
24 | }, | ||
25 | { | ||
26 | USB_DEVICE(USB8388_VID_2, USB8388_PID_2), | ||
27 | }, | ||
28 | {} /* Terminating entry */ | ||
29 | }; | ||
30 | |||
31 | MODULE_DEVICE_TABLE(usb, if_usb_table); | ||
32 | |||
33 | static void if_usb_receive(struct urb *urb); | ||
34 | static void if_usb_receive_fwload(struct urb *urb); | ||
35 | |||
36 | /** | ||
37 | * @brief call back function to handle the status of the URB | ||
38 | * @param urb pointer to urb structure | ||
39 | * @return N/A | ||
40 | */ | ||
41 | static void if_usb_write_bulk_callback(struct urb *urb) | ||
42 | { | ||
43 | wlan_private *priv = (wlan_private *) (urb->context); | ||
44 | wlan_adapter *adapter = priv->adapter; | ||
45 | struct net_device *dev = priv->wlan_dev.netdev; | ||
46 | |||
47 | /* handle the transmission complete validations */ | ||
48 | |||
49 | if (urb->status != 0) { | ||
50 | /* print the failure status number for debug */ | ||
51 | lbs_pr_info("URB in failure status\n"); | ||
52 | } else { | ||
53 | lbs_dev_dbg(2, &urb->dev->dev, "URB status is successfull\n"); | ||
54 | lbs_dev_dbg(2, &urb->dev->dev, "Actual length transmitted %d\n", | ||
55 | urb->actual_length); | ||
56 | priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; | ||
57 | /* Wake main thread if commands are pending */ | ||
58 | if (!adapter->cur_cmd) | ||
59 | wake_up_interruptible(&priv->mainthread.waitq); | ||
60 | if ((adapter->connect_status == libertas_connected)) | ||
61 | netif_wake_queue(dev); | ||
62 | } | ||
63 | |||
64 | return; | ||
65 | } | ||
66 | |||
67 | /** | ||
68 | * @brief free tx/rx urb, skb and rx buffer | ||
69 | * @param cardp pointer usb_card_rec | ||
70 | * @return N/A | ||
71 | */ | ||
72 | void if_usb_free(struct usb_card_rec *cardp) | ||
73 | { | ||
74 | ENTER(); | ||
75 | |||
76 | /* Unlink tx & rx urb */ | ||
77 | usb_kill_urb(cardp->tx_urb); | ||
78 | usb_kill_urb(cardp->rx_urb); | ||
79 | |||
80 | usb_free_urb(cardp->tx_urb); | ||
81 | cardp->tx_urb = NULL; | ||
82 | |||
83 | usb_free_urb(cardp->rx_urb); | ||
84 | cardp->rx_urb = NULL; | ||
85 | |||
86 | kfree(cardp->bulk_out_buffer); | ||
87 | cardp->bulk_out_buffer = NULL; | ||
88 | |||
89 | LEAVE(); | ||
90 | return; | ||
91 | } | ||
92 | |||
93 | /** | ||
94 | * @brief sets the configuration values | ||
95 | * @param ifnum interface number | ||
96 | * @param id pointer to usb_device_id | ||
97 | * @return 0 on success, error code on failure | ||
98 | */ | ||
99 | static int if_usb_probe(struct usb_interface *intf, | ||
100 | const struct usb_device_id *id) | ||
101 | { | ||
102 | struct usb_device *udev; | ||
103 | struct usb_host_interface *iface_desc; | ||
104 | struct usb_endpoint_descriptor *endpoint; | ||
105 | wlan_private *pwlanpriv; | ||
106 | struct usb_card_rec *usb_cardp; | ||
107 | int i; | ||
108 | |||
109 | udev = interface_to_usbdev(intf); | ||
110 | |||
111 | usb_cardp = kzalloc(sizeof(struct usb_card_rec), GFP_KERNEL); | ||
112 | if (!usb_cardp) { | ||
113 | lbs_pr_err("Out of memory allocating private data.\n"); | ||
114 | goto error; | ||
115 | } | ||
116 | |||
117 | usb_cardp->udev = udev; | ||
118 | iface_desc = intf->cur_altsetting; | ||
119 | |||
120 | lbs_dev_dbg(1, &udev->dev, "bcdUSB = 0x%X bDeviceClass = 0x%X" | ||
121 | " bDeviceSubClass = 0x%X, bDeviceProtocol = 0x%X\n", | ||
122 | udev->descriptor.bcdUSB, | ||
123 | udev->descriptor.bDeviceClass, | ||
124 | udev->descriptor.bDeviceSubClass, | ||
125 | udev->descriptor.bDeviceProtocol); | ||
126 | |||
127 | for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) { | ||
128 | endpoint = &iface_desc->endpoint[i].desc; | ||
129 | if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) | ||
130 | && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | ||
131 | USB_ENDPOINT_XFER_BULK)) { | ||
132 | /* we found a bulk in endpoint */ | ||
133 | lbs_dev_dbg(1, &udev->dev, "Bulk in size is %d\n", | ||
134 | endpoint->wMaxPacketSize); | ||
135 | if (! | ||
136 | (usb_cardp->rx_urb = | ||
137 | usb_alloc_urb(0, GFP_KERNEL))) { | ||
138 | lbs_dev_dbg(1, &udev->dev, | ||
139 | "Rx URB allocation failed\n"); | ||
140 | goto dealloc; | ||
141 | } | ||
142 | usb_cardp->rx_urb_recall = 0; | ||
143 | |||
144 | usb_cardp->bulk_in_size = | ||
145 | endpoint->wMaxPacketSize; | ||
146 | usb_cardp->bulk_in_endpointAddr = | ||
147 | (endpoint-> | ||
148 | bEndpointAddress & USB_ENDPOINT_NUMBER_MASK); | ||
149 | lbs_dev_dbg(1, &udev->dev, "in_endpoint = %d\n", | ||
150 | endpoint->bEndpointAddress); | ||
151 | } | ||
152 | |||
153 | if (((endpoint-> | ||
154 | bEndpointAddress & USB_ENDPOINT_DIR_MASK) == | ||
155 | USB_DIR_OUT) | ||
156 | && ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == | ||
157 | USB_ENDPOINT_XFER_BULK)) { | ||
158 | /* We found bulk out endpoint */ | ||
159 | if (! | ||
160 | (usb_cardp->tx_urb = | ||
161 | usb_alloc_urb(0, GFP_KERNEL))) { | ||
162 | lbs_dev_dbg(1,&udev->dev, | ||
163 | "Tx URB allocation failed\n"); | ||
164 | goto dealloc; | ||
165 | } | ||
166 | |||
167 | usb_cardp->bulk_out_size = | ||
168 | endpoint->wMaxPacketSize; | ||
169 | lbs_dev_dbg(1, &udev->dev, | ||
170 | "Bulk out size is %d\n", | ||
171 | endpoint->wMaxPacketSize); | ||
172 | usb_cardp->bulk_out_endpointAddr = | ||
173 | endpoint->bEndpointAddress; | ||
174 | lbs_dev_dbg(1, &udev->dev, "out_endpoint = %d\n", | ||
175 | endpoint->bEndpointAddress); | ||
176 | usb_cardp->bulk_out_buffer = | ||
177 | kmalloc(MRVDRV_ETH_TX_PACKET_BUFFER_SIZE, | ||
178 | GFP_KERNEL); | ||
179 | |||
180 | if (!usb_cardp->bulk_out_buffer) { | ||
181 | lbs_dev_dbg(1, &udev->dev, | ||
182 | "Could not allocate buffer\n"); | ||
183 | goto dealloc; | ||
184 | } | ||
185 | } | ||
186 | } | ||
187 | |||
188 | |||
189 | /* At this point wlan_add_card() will be called. Don't worry | ||
190 | * about keeping pwlanpriv around since it will be set on our | ||
191 | * usb device data in -> add() -> libertas_sbi_register_dev(). | ||
192 | */ | ||
193 | if (!(pwlanpriv = wlan_add_card(usb_cardp))) | ||
194 | goto dealloc; | ||
195 | |||
196 | usb_get_dev(udev); | ||
197 | usb_set_intfdata(intf, usb_cardp); | ||
198 | |||
199 | /* | ||
200 | * return card structure, which can be got back in the | ||
201 | * diconnect function as the ptr | ||
202 | * argument. | ||
203 | */ | ||
204 | return 0; | ||
205 | |||
206 | dealloc: | ||
207 | if_usb_free(usb_cardp); | ||
208 | |||
209 | error: | ||
210 | return -ENOMEM; | ||
211 | } | ||
212 | |||
213 | /** | ||
214 | * @brief free resource and cleanup | ||
215 | * @param udev pointer to usb_device | ||
216 | * @param ptr pointer to usb_cardp | ||
217 | * @return N/A | ||
218 | */ | ||
219 | static void if_usb_disconnect(struct usb_interface *intf) | ||
220 | { | ||
221 | struct usb_card_rec *cardp = usb_get_intfdata(intf); | ||
222 | wlan_private *priv = (wlan_private *) cardp->priv; | ||
223 | wlan_adapter *adapter = NULL; | ||
224 | |||
225 | adapter = priv->adapter; | ||
226 | |||
227 | /* | ||
228 | * Update Surprise removed to TRUE | ||
229 | */ | ||
230 | adapter->surpriseremoved = 1; | ||
231 | |||
232 | /* card is removed and we can call wlan_remove_card */ | ||
233 | lbs_dev_dbg(1, &cardp->udev->dev, "call remove card\n"); | ||
234 | wlan_remove_card(cardp); | ||
235 | |||
236 | /* Unlink and free urb */ | ||
237 | if_usb_free(cardp); | ||
238 | |||
239 | usb_set_intfdata(intf, NULL); | ||
240 | usb_put_dev(interface_to_usbdev(intf)); | ||
241 | |||
242 | return; | ||
243 | } | ||
244 | |||
245 | /** | ||
246 | * @brief This function download FW | ||
247 | * @param priv pointer to wlan_private | ||
248 | * @return 0 | ||
249 | */ | ||
250 | static int if_prog_firmware(wlan_private * priv) | ||
251 | { | ||
252 | struct usb_card_rec *cardp = priv->wlan_dev.card; | ||
253 | struct FWData *fwdata; | ||
254 | struct fwheader *fwheader; | ||
255 | u8 *firmware = priv->firmware->data; | ||
256 | |||
257 | fwdata = kmalloc(sizeof(struct FWData), GFP_ATOMIC); | ||
258 | |||
259 | if (!fwdata) | ||
260 | return -1; | ||
261 | |||
262 | fwheader = &fwdata->fwheader; | ||
263 | |||
264 | if (!cardp->CRC_OK) { | ||
265 | cardp->totalbytes = cardp->fwlastblksent; | ||
266 | cardp->fwseqnum = cardp->lastseqnum - 1; | ||
267 | } | ||
268 | |||
269 | lbs_dev_dbg(2, &cardp->udev->dev, "totalbytes = %d\n", | ||
270 | cardp->totalbytes); | ||
271 | |||
272 | memcpy(fwheader, &firmware[cardp->totalbytes], | ||
273 | sizeof(struct fwheader)); | ||
274 | |||
275 | cardp->fwlastblksent = cardp->totalbytes; | ||
276 | cardp->totalbytes += sizeof(struct fwheader); | ||
277 | |||
278 | lbs_dev_dbg(2, &cardp->udev->dev,"Copy Data\n"); | ||
279 | memcpy(fwdata->data, &firmware[cardp->totalbytes], | ||
280 | fwdata->fwheader.datalength); | ||
281 | |||
282 | lbs_dev_dbg(2, &cardp->udev->dev, | ||
283 | "Data length = %d\n", fwdata->fwheader.datalength); | ||
284 | |||
285 | cardp->fwseqnum = cardp->fwseqnum + 1; | ||
286 | |||
287 | fwdata->seqnum = cardp->fwseqnum; | ||
288 | cardp->lastseqnum = fwdata->seqnum; | ||
289 | cardp->totalbytes += fwdata->fwheader.datalength; | ||
290 | |||
291 | if (fwheader->dnldcmd == FW_HAS_DATA_TO_RECV) { | ||
292 | lbs_dev_dbg(2, &cardp->udev->dev, "There is data to follow\n"); | ||
293 | lbs_dev_dbg(2, &cardp->udev->dev, | ||
294 | "seqnum = %d totalbytes = %d\n", cardp->fwseqnum, | ||
295 | cardp->totalbytes); | ||
296 | memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); | ||
297 | usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); | ||
298 | |||
299 | } else if (fwdata->fwheader.dnldcmd == FW_HAS_LAST_BLOCK) { | ||
300 | lbs_dev_dbg(2, &cardp->udev->dev, | ||
301 | "Host has finished FW downloading\n"); | ||
302 | lbs_dev_dbg(2, &cardp->udev->dev, | ||
303 | "Donwloading FW JUMP BLOCK\n"); | ||
304 | memcpy(cardp->bulk_out_buffer, fwheader, FW_DATA_XMIT_SIZE); | ||
305 | usb_tx_block(priv, cardp->bulk_out_buffer, FW_DATA_XMIT_SIZE); | ||
306 | cardp->fwfinalblk = 1; | ||
307 | } | ||
308 | |||
309 | lbs_dev_dbg(2, &cardp->udev->dev, | ||
310 | "The firmware download is done size is %d\n", | ||
311 | cardp->totalbytes); | ||
312 | |||
313 | kfree(fwdata); | ||
314 | |||
315 | return 0; | ||
316 | } | ||
317 | |||
318 | static int libertas_do_reset(wlan_private *priv) | ||
319 | { | ||
320 | int ret; | ||
321 | struct usb_card_rec *cardp = priv->wlan_dev.card; | ||
322 | |||
323 | ret = usb_reset_device(cardp->udev); | ||
324 | if (!ret) { | ||
325 | msleep(10); | ||
326 | reset_device(priv); | ||
327 | msleep(10); | ||
328 | } | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * @brief This function transfer the data to the device. | ||
334 | * @param priv pointer to wlan_private | ||
335 | * @param payload pointer to payload data | ||
336 | * @param nb data length | ||
337 | * @return 0 or -1 | ||
338 | */ | ||
339 | int usb_tx_block(wlan_private * priv, u8 * payload, u16 nb) | ||
340 | { | ||
341 | /* pointer to card structure */ | ||
342 | struct usb_card_rec *cardp = priv->wlan_dev.card; | ||
343 | int ret = -1; | ||
344 | |||
345 | /* check if device is removed */ | ||
346 | if (priv->adapter->surpriseremoved) { | ||
347 | lbs_dev_dbg(1, &cardp->udev->dev, "Device removed\n"); | ||
348 | goto tx_ret; | ||
349 | } | ||
350 | |||
351 | usb_fill_bulk_urb(cardp->tx_urb, cardp->udev, | ||
352 | usb_sndbulkpipe(cardp->udev, | ||
353 | cardp->bulk_out_endpointAddr), | ||
354 | payload, nb, if_usb_write_bulk_callback, priv); | ||
355 | |||
356 | cardp->tx_urb->transfer_flags |= URB_ZERO_PACKET; | ||
357 | |||
358 | if ((ret = usb_submit_urb(cardp->tx_urb, GFP_ATOMIC))) { | ||
359 | /* transfer failed */ | ||
360 | lbs_dev_dbg(1, &cardp->udev->dev, "usb_submit_urb failed\n"); | ||
361 | ret = -1; | ||
362 | } else { | ||
363 | lbs_dev_dbg(2, &cardp->udev->dev, "usb_submit_urb success\n"); | ||
364 | ret = 0; | ||
365 | } | ||
366 | |||
367 | tx_ret: | ||
368 | return ret; | ||
369 | } | ||
370 | |||
371 | static int __if_usb_submit_rx_urb(wlan_private * priv, | ||
372 | void (*callbackfn) | ||
373 | (struct urb *urb)) | ||
374 | { | ||
375 | struct usb_card_rec *cardp = priv->wlan_dev.card; | ||
376 | struct sk_buff *skb; | ||
377 | struct read_cb_info *rinfo = &cardp->rinfo; | ||
378 | int ret = -1; | ||
379 | |||
380 | if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) { | ||
381 | lbs_pr_err("No free skb\n"); | ||
382 | goto rx_ret; | ||
383 | } | ||
384 | |||
385 | rinfo->skb = skb; | ||
386 | |||
387 | /* Fill the receive configuration URB and initialise the Rx call back */ | ||
388 | usb_fill_bulk_urb(cardp->rx_urb, cardp->udev, | ||
389 | usb_rcvbulkpipe(cardp->udev, | ||
390 | cardp->bulk_in_endpointAddr), | ||
391 | skb->tail + IPFIELD_ALIGN_OFFSET, | ||
392 | MRVDRV_ETH_RX_PACKET_BUFFER_SIZE, callbackfn, | ||
393 | rinfo); | ||
394 | |||
395 | cardp->rx_urb->transfer_flags |= URB_ZERO_PACKET; | ||
396 | |||
397 | lbs_dev_dbg(2, &cardp->udev->dev, "Pointer for rx_urb %p\n", cardp->rx_urb); | ||
398 | if ((ret = usb_submit_urb(cardp->rx_urb, GFP_ATOMIC))) { | ||
399 | /* handle failure conditions */ | ||
400 | lbs_dev_dbg(1, &cardp->udev->dev, "Submit Rx URB failed\n"); | ||
401 | ret = -1; | ||
402 | } else { | ||
403 | lbs_dev_dbg(2, &cardp->udev->dev, "Submit Rx URB success\n"); | ||
404 | ret = 0; | ||
405 | } | ||
406 | |||
407 | rx_ret: | ||
408 | return ret; | ||
409 | } | ||
410 | |||
411 | static inline int if_usb_submit_rx_urb_fwload(wlan_private * priv) | ||
412 | { | ||
413 | return __if_usb_submit_rx_urb(priv, &if_usb_receive_fwload); | ||
414 | } | ||
415 | |||
416 | static inline int if_usb_submit_rx_urb(wlan_private * priv) | ||
417 | { | ||
418 | return __if_usb_submit_rx_urb(priv, &if_usb_receive); | ||
419 | } | ||
420 | |||
421 | static void if_usb_receive_fwload(struct urb *urb) | ||
422 | { | ||
423 | struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; | ||
424 | wlan_private *priv = rinfo->priv; | ||
425 | struct sk_buff *skb = rinfo->skb; | ||
426 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; | ||
427 | struct fwsyncheader *syncfwheader; | ||
428 | struct bootcmdrespStr bootcmdresp; | ||
429 | |||
430 | if (urb->status) { | ||
431 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
432 | "URB status is failed during fw load\n"); | ||
433 | kfree_skb(skb); | ||
434 | return; | ||
435 | } | ||
436 | |||
437 | if (cardp->bootcmdresp == 0) { | ||
438 | memcpy (&bootcmdresp, skb->data + IPFIELD_ALIGN_OFFSET, | ||
439 | sizeof(bootcmdresp)); | ||
440 | if (cardp->udev->descriptor.bcdDevice < 0x3106) { | ||
441 | kfree_skb(skb); | ||
442 | if_usb_submit_rx_urb_fwload(priv); | ||
443 | cardp->bootcmdresp = 1; | ||
444 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
445 | "Received valid boot command response\n"); | ||
446 | return; | ||
447 | } | ||
448 | if (bootcmdresp.u32magicnumber != BOOT_CMD_MAGIC_NUMBER) { | ||
449 | lbs_pr_info( | ||
450 | "boot cmd response wrong magic number (0x%x)\n", | ||
451 | bootcmdresp.u32magicnumber); | ||
452 | } else if (bootcmdresp.u8cmd_tag != BOOT_CMD_FW_BY_USB) { | ||
453 | lbs_pr_info( | ||
454 | "boot cmd response cmd_tag error (%d)\n", | ||
455 | bootcmdresp.u8cmd_tag); | ||
456 | } else if (bootcmdresp.u8result != BOOT_CMD_RESP_OK) { | ||
457 | lbs_pr_info( | ||
458 | "boot cmd response result error (%d)\n", | ||
459 | bootcmdresp.u8result); | ||
460 | } else { | ||
461 | cardp->bootcmdresp = 1; | ||
462 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
463 | "Received valid boot command response\n"); | ||
464 | } | ||
465 | kfree_skb(skb); | ||
466 | if_usb_submit_rx_urb_fwload(priv); | ||
467 | return; | ||
468 | } | ||
469 | |||
470 | syncfwheader = kmalloc(sizeof(struct fwsyncheader), GFP_ATOMIC); | ||
471 | if (!syncfwheader) { | ||
472 | lbs_dev_dbg(1, &cardp->udev->dev, "Failure to allocate syncfwheader\n"); | ||
473 | kfree_skb(skb); | ||
474 | return; | ||
475 | } | ||
476 | |||
477 | memcpy(syncfwheader, skb->data + IPFIELD_ALIGN_OFFSET, | ||
478 | sizeof(struct fwsyncheader)); | ||
479 | |||
480 | if (!syncfwheader->cmd) { | ||
481 | lbs_dev_dbg(2, &cardp->udev->dev, | ||
482 | "FW received Blk with correct CRC\n"); | ||
483 | lbs_dev_dbg(2, &cardp->udev->dev, | ||
484 | "FW received Blk seqnum = %d\n", | ||
485 | syncfwheader->seqnum); | ||
486 | cardp->CRC_OK = 1; | ||
487 | } else { | ||
488 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
489 | "FW received Blk with CRC error\n"); | ||
490 | cardp->CRC_OK = 0; | ||
491 | } | ||
492 | |||
493 | kfree_skb(skb); | ||
494 | |||
495 | if (cardp->fwfinalblk) { | ||
496 | cardp->fwdnldover = 1; | ||
497 | goto exit; | ||
498 | } | ||
499 | |||
500 | if_prog_firmware(priv); | ||
501 | |||
502 | if_usb_submit_rx_urb_fwload(priv); | ||
503 | exit: | ||
504 | kfree(syncfwheader); | ||
505 | |||
506 | return; | ||
507 | |||
508 | } | ||
509 | |||
510 | #define MRVDRV_MIN_PKT_LEN 30 | ||
511 | |||
512 | static inline void process_cmdtypedata(int recvlength, struct sk_buff *skb, | ||
513 | struct usb_card_rec *cardp, | ||
514 | wlan_private *priv) | ||
515 | { | ||
516 | if (recvlength > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE + | ||
517 | MESSAGE_HEADER_LEN || recvlength < MRVDRV_MIN_PKT_LEN) { | ||
518 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
519 | "Packet length is Invalid\n"); | ||
520 | kfree_skb(skb); | ||
521 | return; | ||
522 | } | ||
523 | |||
524 | skb_reserve(skb, IPFIELD_ALIGN_OFFSET); | ||
525 | skb_put(skb, recvlength); | ||
526 | skb_pull(skb, MESSAGE_HEADER_LEN); | ||
527 | libertas_process_rxed_packet(priv, skb); | ||
528 | priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN); | ||
529 | } | ||
530 | |||
531 | static inline void process_cmdrequest(int recvlength, u8 *recvbuff, | ||
532 | struct sk_buff *skb, | ||
533 | struct usb_card_rec *cardp, | ||
534 | wlan_private *priv) | ||
535 | { | ||
536 | u8 *cmdbuf; | ||
537 | if (recvlength > MRVDRV_SIZE_OF_CMD_BUFFER) { | ||
538 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
539 | "The receive buffer is too large\n"); | ||
540 | kfree_skb(skb); | ||
541 | return; | ||
542 | } | ||
543 | |||
544 | if (!in_interrupt()) | ||
545 | BUG(); | ||
546 | |||
547 | spin_lock(&priv->adapter->driver_lock); | ||
548 | /* take care of cur_cmd = NULL case by reading the | ||
549 | * data to clear the interrupt */ | ||
550 | if (!priv->adapter->cur_cmd) { | ||
551 | cmdbuf = priv->wlan_dev.upld_buf; | ||
552 | priv->adapter->hisregcpy &= ~his_cmdupldrdy; | ||
553 | } else | ||
554 | cmdbuf = priv->adapter->cur_cmd->bufvirtualaddr; | ||
555 | |||
556 | cardp->usb_int_cause |= his_cmdupldrdy; | ||
557 | priv->wlan_dev.upld_len = (recvlength - MESSAGE_HEADER_LEN); | ||
558 | memcpy(cmdbuf, recvbuff + MESSAGE_HEADER_LEN, | ||
559 | priv->wlan_dev.upld_len); | ||
560 | |||
561 | kfree_skb(skb); | ||
562 | libertas_interrupt(priv->wlan_dev.netdev); | ||
563 | spin_unlock(&priv->adapter->driver_lock); | ||
564 | |||
565 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
566 | "Wake up main thread to handle cmd response\n"); | ||
567 | |||
568 | return; | ||
569 | } | ||
570 | |||
571 | /** | ||
572 | * @brief This function reads of the packet into the upload buff, | ||
573 | * wake up the main thread and initialise the Rx callack. | ||
574 | * | ||
575 | * @param urb pointer to struct urb | ||
576 | * @return N/A | ||
577 | */ | ||
578 | static void if_usb_receive(struct urb *urb) | ||
579 | { | ||
580 | struct read_cb_info *rinfo = (struct read_cb_info *)urb->context; | ||
581 | wlan_private *priv = rinfo->priv; | ||
582 | struct sk_buff *skb = rinfo->skb; | ||
583 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; | ||
584 | |||
585 | int recvlength = urb->actual_length; | ||
586 | u8 *recvbuff = NULL; | ||
587 | u32 recvtype; | ||
588 | |||
589 | ENTER(); | ||
590 | |||
591 | if (recvlength) { | ||
592 | if (urb->status) { | ||
593 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
594 | "URB status is failed\n"); | ||
595 | kfree_skb(skb); | ||
596 | goto setup_for_next; | ||
597 | } | ||
598 | |||
599 | recvbuff = skb->data + IPFIELD_ALIGN_OFFSET; | ||
600 | memcpy(&recvtype, recvbuff, sizeof(u32)); | ||
601 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
602 | "Recv length = 0x%x\n", recvlength); | ||
603 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
604 | "Receive type = 0x%X\n", recvtype); | ||
605 | recvtype = le32_to_cpu(recvtype); | ||
606 | lbs_dev_dbg(1, &cardp->udev->dev, | ||
607 | "Receive type after = 0x%X\n", recvtype); | ||
608 | } else if (urb->status) | ||
609 | goto rx_exit; | ||
610 | |||
611 | |||
612 | switch (recvtype) { | ||
613 | case CMD_TYPE_DATA: | ||
614 | process_cmdtypedata(recvlength, skb, cardp, priv); | ||
615 | break; | ||
616 | |||
617 | case CMD_TYPE_REQUEST: | ||
618 | process_cmdrequest(recvlength, recvbuff, skb, cardp, priv); | ||
619 | break; | ||
620 | |||
621 | case CMD_TYPE_INDICATION: | ||
622 | /* Event cause handling */ | ||
623 | spin_lock(&priv->adapter->driver_lock); | ||
624 | cardp->usb_event_cause = *(u32 *) (recvbuff + MESSAGE_HEADER_LEN); | ||
625 | lbs_dev_dbg(1, &cardp->udev->dev,"**EVENT** 0x%X\n", | ||
626 | cardp->usb_event_cause); | ||
627 | if (cardp->usb_event_cause & 0xffff0000) { | ||
628 | libertas_send_tx_feedback(priv); | ||
629 | break; | ||
630 | } | ||
631 | cardp->usb_event_cause = le32_to_cpu(cardp->usb_event_cause) << 3; | ||
632 | cardp->usb_int_cause |= his_cardevent; | ||
633 | kfree_skb(skb); | ||
634 | libertas_interrupt(priv->wlan_dev.netdev); | ||
635 | spin_unlock(&priv->adapter->driver_lock); | ||
636 | goto rx_exit; | ||
637 | default: | ||
638 | kfree_skb(skb); | ||
639 | break; | ||
640 | } | ||
641 | |||
642 | setup_for_next: | ||
643 | if_usb_submit_rx_urb(priv); | ||
644 | rx_exit: | ||
645 | LEAVE(); | ||
646 | return; | ||
647 | } | ||
648 | |||
649 | /** | ||
650 | * @brief This function downloads data to FW | ||
651 | * @param priv pointer to wlan_private structure | ||
652 | * @param type type of data | ||
653 | * @param buf pointer to data buffer | ||
654 | * @param len number of bytes | ||
655 | * @return 0 or -1 | ||
656 | */ | ||
657 | int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb) | ||
658 | { | ||
659 | int ret = -1; | ||
660 | u32 tmp; | ||
661 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; | ||
662 | |||
663 | lbs_dev_dbg(1, &cardp->udev->dev,"*** type = %u\n", type); | ||
664 | lbs_dev_dbg(1, &cardp->udev->dev,"size after = %d\n", nb); | ||
665 | |||
666 | if (type == MVMS_CMD) { | ||
667 | tmp = cpu_to_le32(CMD_TYPE_REQUEST); | ||
668 | priv->wlan_dev.dnld_sent = DNLD_CMD_SENT; | ||
669 | memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, | ||
670 | MESSAGE_HEADER_LEN); | ||
671 | |||
672 | } else { | ||
673 | tmp = cpu_to_le32(CMD_TYPE_DATA); | ||
674 | priv->wlan_dev.dnld_sent = DNLD_DATA_SENT; | ||
675 | memcpy(cardp->bulk_out_buffer, (u8 *) & tmp, | ||
676 | MESSAGE_HEADER_LEN); | ||
677 | } | ||
678 | |||
679 | memcpy((cardp->bulk_out_buffer + MESSAGE_HEADER_LEN), payload, nb); | ||
680 | |||
681 | ret = | ||
682 | usb_tx_block(priv, cardp->bulk_out_buffer, nb + MESSAGE_HEADER_LEN); | ||
683 | |||
684 | return ret; | ||
685 | } | ||
686 | |||
687 | /* called with adapter->driver_lock held */ | ||
688 | int libertas_sbi_get_int_status(wlan_private * priv, u8 * ireg) | ||
689 | { | ||
690 | struct usb_card_rec *cardp = priv->wlan_dev.card; | ||
691 | |||
692 | *ireg = cardp->usb_int_cause; | ||
693 | cardp->usb_int_cause = 0; | ||
694 | |||
695 | lbs_dev_dbg(1, &cardp->udev->dev,"Int cause is 0x%X\n", *ireg); | ||
696 | |||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | int libertas_sbi_read_event_cause(wlan_private * priv) | ||
701 | { | ||
702 | struct usb_card_rec *cardp = priv->wlan_dev.card; | ||
703 | priv->adapter->eventcause = cardp->usb_event_cause; | ||
704 | /* Re-submit rx urb here to avoid event lost issue */ | ||
705 | if_usb_submit_rx_urb(priv); | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | int reset_device(wlan_private *priv) | ||
710 | { | ||
711 | int ret; | ||
712 | |||
713 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_reset, | ||
714 | cmd_act_halt, 0, 0, NULL); | ||
715 | msleep_interruptible(10); | ||
716 | |||
717 | return ret; | ||
718 | } | ||
719 | |||
720 | int libertas_sbi_unregister_dev(wlan_private * priv) | ||
721 | { | ||
722 | int ret = 0; | ||
723 | |||
724 | /* Need to send a Reset command to device before USB resources freed | ||
725 | * and wlan_remove_card() called, then device can handle FW download | ||
726 | * again. | ||
727 | */ | ||
728 | if (priv) | ||
729 | reset_device(priv); | ||
730 | |||
731 | return ret; | ||
732 | } | ||
733 | |||
734 | |||
735 | /** | ||
736 | * @brief This function register usb device and initialize parameter | ||
737 | * @param priv pointer to wlan_private | ||
738 | * @return 0 or -1 | ||
739 | */ | ||
740 | int libertas_sbi_register_dev(wlan_private * priv) | ||
741 | { | ||
742 | |||
743 | struct usb_card_rec *cardp = (struct usb_card_rec *)priv->wlan_dev.card; | ||
744 | ENTER(); | ||
745 | |||
746 | cardp->priv = priv; | ||
747 | cardp->eth_dev = priv->wlan_dev.netdev; | ||
748 | priv->hotplug_device = &(cardp->udev->dev); | ||
749 | |||
750 | SET_NETDEV_DEV(cardp->eth_dev, &(cardp->udev->dev)); | ||
751 | |||
752 | lbs_dev_dbg(1, &cardp->udev->dev, "udev pointer is at %p\n", | ||
753 | cardp->udev); | ||
754 | |||
755 | LEAVE(); | ||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | |||
760 | |||
761 | int libertas_sbi_prog_firmware(wlan_private * priv) | ||
762 | { | ||
763 | struct usb_card_rec *cardp = priv->wlan_dev.card; | ||
764 | int i = 0; | ||
765 | static int reset_count = 10; | ||
766 | |||
767 | ENTER(); | ||
768 | |||
769 | cardp->rinfo.priv = priv; | ||
770 | |||
771 | restart: | ||
772 | if (if_usb_submit_rx_urb_fwload(priv) < 0) { | ||
773 | lbs_dev_dbg(1, &cardp->udev->dev, "URB submission is failed\n"); | ||
774 | LEAVE(); | ||
775 | return -1; | ||
776 | } | ||
777 | |||
778 | #ifdef SUPPORT_BOOT_COMMAND | ||
779 | cardp->bootcmdresp = 0; | ||
780 | do { | ||
781 | int j = 0; | ||
782 | i++; | ||
783 | /* Issue Boot command = 1, Boot from Download-FW */ | ||
784 | if_usb_issue_boot_command(priv, BOOT_CMD_FW_BY_USB); | ||
785 | /* wait for command response */ | ||
786 | do { | ||
787 | j++; | ||
788 | msleep_interruptible(100); | ||
789 | } while (cardp->bootcmdresp == 0 && j < 10); | ||
790 | } while (cardp->bootcmdresp == 0 && i < 5); | ||
791 | |||
792 | if (cardp->bootcmdresp == 0) { | ||
793 | if (--reset_count >= 0) { | ||
794 | libertas_do_reset(priv); | ||
795 | goto restart; | ||
796 | } | ||
797 | return -1; | ||
798 | } | ||
799 | #endif | ||
800 | |||
801 | i = 0; | ||
802 | priv->adapter->fw_ready = 0; | ||
803 | |||
804 | cardp->totalbytes = 0; | ||
805 | cardp->fwlastblksent = 0; | ||
806 | cardp->CRC_OK = 1; | ||
807 | cardp->fwdnldover = 0; | ||
808 | cardp->fwseqnum = -1; | ||
809 | cardp->totalbytes = 0; | ||
810 | cardp->fwfinalblk = 0; | ||
811 | |||
812 | if_prog_firmware(priv); | ||
813 | |||
814 | do { | ||
815 | lbs_dev_dbg(1, &cardp->udev->dev,"Wlan sched timeout\n"); | ||
816 | i++; | ||
817 | msleep_interruptible(100); | ||
818 | if (priv->adapter->surpriseremoved || i >= 20) | ||
819 | break; | ||
820 | } while (!cardp->fwdnldover); | ||
821 | |||
822 | if (!cardp->fwdnldover) { | ||
823 | lbs_pr_info("failed to load fw, resetting device!\n"); | ||
824 | if (--reset_count >= 0) { | ||
825 | libertas_do_reset(priv); | ||
826 | goto restart; | ||
827 | } | ||
828 | |||
829 | lbs_pr_info("FW download failure, time = %d ms\n", i * 100); | ||
830 | LEAVE(); | ||
831 | return -1; | ||
832 | } | ||
833 | |||
834 | if_usb_submit_rx_urb(priv); | ||
835 | |||
836 | /* Delay 200 ms to waiting for the FW ready */ | ||
837 | msleep_interruptible(200); | ||
838 | |||
839 | priv->adapter->fw_ready = 1; | ||
840 | |||
841 | LEAVE(); | ||
842 | return 0; | ||
843 | } | ||
844 | |||
845 | /** | ||
846 | * @brief Given a usb_card_rec return its wlan_private | ||
847 | * @param card pointer to a usb_card_rec | ||
848 | * @return pointer to wlan_private | ||
849 | */ | ||
850 | wlan_private *libertas_sbi_get_priv(void *card) | ||
851 | { | ||
852 | struct usb_card_rec *cardp = card; | ||
853 | return cardp->priv; | ||
854 | } | ||
855 | |||
856 | #ifdef ENABLE_PM | ||
857 | int libertas_sbi_suspend(wlan_private * priv) | ||
858 | { | ||
859 | return 0; | ||
860 | } | ||
861 | |||
862 | int libertas_sbi_resume(wlan_private * priv) | ||
863 | { | ||
864 | return 0; | ||
865 | } | ||
866 | #endif | ||
867 | |||
868 | #ifdef CONFIG_PM | ||
869 | static int if_usb_suspend(struct usb_interface *intf, pm_message_t message) | ||
870 | { | ||
871 | struct usb_card_rec *cardp = usb_get_intfdata(intf); | ||
872 | wlan_private *priv = cardp->priv; | ||
873 | |||
874 | ENTER(); | ||
875 | |||
876 | if (priv->adapter->psstate != PS_STATE_FULL_POWER) | ||
877 | return -1; | ||
878 | |||
879 | netif_device_detach(cardp->eth_dev); | ||
880 | |||
881 | /* Unlink tx & rx urb */ | ||
882 | usb_kill_urb(cardp->tx_urb); | ||
883 | usb_kill_urb(cardp->rx_urb); | ||
884 | |||
885 | cardp->rx_urb_recall = 1; | ||
886 | |||
887 | LEAVE(); | ||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | static int if_usb_resume(struct usb_interface *intf) | ||
892 | { | ||
893 | struct usb_card_rec *cardp = usb_get_intfdata(intf); | ||
894 | |||
895 | ENTER(); | ||
896 | |||
897 | cardp->rx_urb_recall = 0; | ||
898 | |||
899 | if_usb_submit_rx_urb(cardp->priv); | ||
900 | |||
901 | netif_device_attach(cardp->eth_dev); | ||
902 | |||
903 | LEAVE(); | ||
904 | return 0; | ||
905 | } | ||
906 | #else | ||
907 | #define if_usb_suspend NULL | ||
908 | #define if_usb_resume NULL | ||
909 | #endif | ||
910 | |||
911 | static struct usb_driver if_usb_driver = { | ||
912 | /* driver name */ | ||
913 | .name = usbdriver_name, | ||
914 | /* probe function name */ | ||
915 | .probe = if_usb_probe, | ||
916 | /* disconnect function name */ | ||
917 | .disconnect = if_usb_disconnect, | ||
918 | /* device signature table */ | ||
919 | .id_table = if_usb_table, | ||
920 | .suspend = if_usb_suspend, | ||
921 | .resume = if_usb_resume, | ||
922 | }; | ||
923 | |||
924 | /** | ||
925 | * @brief This function registers driver. | ||
926 | * @param add pointer to add_card callback function | ||
927 | * @param remove pointer to remove card callback function | ||
928 | * @param arg pointer to call back function parameter | ||
929 | * @return dummy success variable | ||
930 | */ | ||
931 | int libertas_sbi_register(void) | ||
932 | { | ||
933 | /* | ||
934 | * API registers the Marvell USB driver | ||
935 | * to the USB system | ||
936 | */ | ||
937 | usb_register(&if_usb_driver); | ||
938 | |||
939 | /* Return success to wlan layer */ | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | /** | ||
944 | * @brief This function removes usb driver. | ||
945 | * @return N/A | ||
946 | */ | ||
947 | void libertas_sbi_unregister(void) | ||
948 | { | ||
949 | /* API unregisters the driver from USB subsystem */ | ||
950 | usb_deregister(&if_usb_driver); | ||
951 | return; | ||
952 | } | ||
diff --git a/drivers/net/wireless/libertas/if_usb.h b/drivers/net/wireless/libertas/if_usb.h new file mode 100644 index 000000000000..785116720bc6 --- /dev/null +++ b/drivers/net/wireless/libertas/if_usb.h | |||
@@ -0,0 +1,109 @@ | |||
1 | /** | ||
2 | * This file contains definition for USB interface. | ||
3 | */ | ||
4 | #define CMD_TYPE_REQUEST 0xF00DFACE | ||
5 | #define CMD_TYPE_DATA 0xBEADC0DE | ||
6 | #define CMD_TYPE_INDICATION 0xBEEFFACE | ||
7 | |||
8 | #define IPFIELD_ALIGN_OFFSET 2 | ||
9 | |||
10 | #define USB8388_VID_1 0x1286 | ||
11 | #define USB8388_PID_1 0x2001 | ||
12 | #define USB8388_VID_2 0x05a3 | ||
13 | #define USB8388_PID_2 0x8388 | ||
14 | |||
15 | #ifdef SUPPORT_BOOT_COMMAND | ||
16 | #define BOOT_CMD_FW_BY_USB 0x01 | ||
17 | #define BOOT_CMD_FW_IN_EEPROM 0x02 | ||
18 | #define BOOT_CMD_UPDATE_BOOT2 0x03 | ||
19 | #define BOOT_CMD_UPDATE_FW 0x04 | ||
20 | #define BOOT_CMD_MAGIC_NUMBER 0x4C56524D /* M=>0x4D,R=>0x52,V=>0x56,L=>0x4C */ | ||
21 | |||
22 | struct bootcmdstr | ||
23 | { | ||
24 | u32 u32magicnumber; | ||
25 | u8 u8cmd_tag; | ||
26 | u8 au8dumy[11]; | ||
27 | }; | ||
28 | |||
29 | #define BOOT_CMD_RESP_OK 0x0001 | ||
30 | #define BOOT_CMD_RESP_FAIL 0x0000 | ||
31 | |||
32 | struct bootcmdrespStr | ||
33 | { | ||
34 | u32 u32magicnumber; | ||
35 | u8 u8cmd_tag; | ||
36 | u8 u8result; | ||
37 | u8 au8dumy[2]; | ||
38 | }; | ||
39 | #endif /* SUPPORT_BOOT_COMMAND */ | ||
40 | |||
41 | /* read callback private data */ | ||
42 | struct read_cb_info { | ||
43 | wlan_private *priv; | ||
44 | struct sk_buff *skb; | ||
45 | }; | ||
46 | |||
47 | /** USB card description structure*/ | ||
48 | struct usb_card_rec { | ||
49 | struct net_device *eth_dev; | ||
50 | struct usb_device *udev; | ||
51 | struct urb *rx_urb, *tx_urb; | ||
52 | void *priv; | ||
53 | struct read_cb_info rinfo; | ||
54 | |||
55 | int bulk_in_size; | ||
56 | u8 bulk_in_endpointAddr; | ||
57 | |||
58 | u8 *bulk_out_buffer; | ||
59 | int bulk_out_size; | ||
60 | u8 bulk_out_endpointAddr; | ||
61 | |||
62 | u8 CRC_OK; | ||
63 | u32 fwseqnum; | ||
64 | u32 lastseqnum; | ||
65 | u32 totalbytes; | ||
66 | u32 fwlastblksent; | ||
67 | u8 fwdnldover; | ||
68 | u8 fwfinalblk; | ||
69 | |||
70 | u32 usb_event_cause; | ||
71 | u8 usb_int_cause; | ||
72 | |||
73 | u8 rx_urb_recall; | ||
74 | |||
75 | u8 bootcmdresp; | ||
76 | }; | ||
77 | |||
78 | /** fwheader */ | ||
79 | struct fwheader { | ||
80 | u32 dnldcmd; | ||
81 | u32 baseaddr; | ||
82 | u32 datalength; | ||
83 | u32 CRC; | ||
84 | }; | ||
85 | |||
86 | #define FW_MAX_DATA_BLK_SIZE 600 | ||
87 | /** FWData */ | ||
88 | struct FWData { | ||
89 | struct fwheader fwheader; | ||
90 | u32 seqnum; | ||
91 | u8 data[FW_MAX_DATA_BLK_SIZE]; | ||
92 | }; | ||
93 | |||
94 | /** fwsyncheader */ | ||
95 | struct fwsyncheader { | ||
96 | u32 cmd; | ||
97 | u32 seqnum; | ||
98 | }; | ||
99 | |||
100 | #define FW_HAS_DATA_TO_RECV 0x00000001 | ||
101 | #define FW_HAS_LAST_BLOCK 0x00000004 | ||
102 | |||
103 | #define FW_DATA_XMIT_SIZE \ | ||
104 | sizeof(struct fwheader) + fwdata->fwheader.datalength + sizeof(u32) | ||
105 | |||
106 | int usb_tx_block(wlan_private *priv, u8 *payload, u16 nb); | ||
107 | void if_usb_free(struct usb_card_rec *cardp); | ||
108 | int if_usb_issue_boot_command(wlan_private *priv, int ivalue); | ||
109 | |||
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c new file mode 100644 index 000000000000..82b39642423a --- /dev/null +++ b/drivers/net/wireless/libertas/ioctl.c | |||
@@ -0,0 +1,2500 @@ | |||
1 | /** | ||
2 | * This file contains ioctl functions | ||
3 | */ | ||
4 | |||
5 | #include <linux/ctype.h> | ||
6 | #include <linux/delay.h> | ||
7 | #include <linux/if.h> | ||
8 | #include <linux/if_arp.h> | ||
9 | #include <linux/wireless.h> | ||
10 | |||
11 | #include <net/iw_handler.h> | ||
12 | #include <net/ieee80211.h> | ||
13 | |||
14 | #include "host.h" | ||
15 | #include "radiotap.h" | ||
16 | #include "decl.h" | ||
17 | #include "defs.h" | ||
18 | #include "dev.h" | ||
19 | #include "join.h" | ||
20 | #include "wext.h" | ||
21 | |||
22 | #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \ | ||
23 | IW_ESSID_MAX_SIZE + \ | ||
24 | IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \ | ||
25 | IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \ | ||
26 | IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */ | ||
27 | |||
28 | #define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ) | ||
29 | |||
30 | static int setrxantenna(wlan_private * priv, int mode) | ||
31 | { | ||
32 | int ret = 0; | ||
33 | wlan_adapter *adapter = priv->adapter; | ||
34 | |||
35 | if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2 | ||
36 | && mode != RF_ANTENNA_AUTO) { | ||
37 | return -EINVAL; | ||
38 | } | ||
39 | |||
40 | adapter->rxantennamode = mode; | ||
41 | |||
42 | lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode); | ||
43 | |||
44 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, | ||
45 | cmd_act_set_rx, | ||
46 | cmd_option_waitforrsp, 0, | ||
47 | &adapter->rxantennamode); | ||
48 | return ret; | ||
49 | } | ||
50 | |||
51 | static int settxantenna(wlan_private * priv, int mode) | ||
52 | { | ||
53 | int ret = 0; | ||
54 | wlan_adapter *adapter = priv->adapter; | ||
55 | |||
56 | if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2) | ||
57 | && (mode != RF_ANTENNA_AUTO)) { | ||
58 | return -EINVAL; | ||
59 | } | ||
60 | |||
61 | adapter->txantennamode = mode; | ||
62 | |||
63 | lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode); | ||
64 | |||
65 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, | ||
66 | cmd_act_set_tx, | ||
67 | cmd_option_waitforrsp, 0, | ||
68 | &adapter->txantennamode); | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | static int getrxantenna(wlan_private * priv, char *buf) | ||
74 | { | ||
75 | int ret = 0; | ||
76 | wlan_adapter *adapter = priv->adapter; | ||
77 | |||
78 | // clear it, so we will know if the value | ||
79 | // returned below is correct or not. | ||
80 | adapter->rxantennamode = 0; | ||
81 | |||
82 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, | ||
83 | cmd_act_get_rx, | ||
84 | cmd_option_waitforrsp, 0, NULL); | ||
85 | |||
86 | if (ret) { | ||
87 | LEAVE(); | ||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode); | ||
92 | |||
93 | return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1; | ||
94 | } | ||
95 | |||
96 | static int gettxantenna(wlan_private * priv, char *buf) | ||
97 | { | ||
98 | int ret = 0; | ||
99 | wlan_adapter *adapter = priv->adapter; | ||
100 | |||
101 | // clear it, so we will know if the value | ||
102 | // returned below is correct or not. | ||
103 | adapter->txantennamode = 0; | ||
104 | |||
105 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, | ||
106 | cmd_act_get_tx, | ||
107 | cmd_option_waitforrsp, 0, NULL); | ||
108 | |||
109 | if (ret) { | ||
110 | LEAVE(); | ||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode); | ||
115 | |||
116 | return sprintf(buf, "0x%04x", adapter->txantennamode) + 1; | ||
117 | } | ||
118 | |||
119 | static int wlan_set_region(wlan_private * priv, u16 region_code) | ||
120 | { | ||
121 | int i; | ||
122 | |||
123 | for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { | ||
124 | // use the region code to search for the index | ||
125 | if (region_code == libertas_region_code_to_index[i]) { | ||
126 | priv->adapter->regiontableindex = (u16) i; | ||
127 | priv->adapter->regioncode = region_code; | ||
128 | break; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | // if it's unidentified region code | ||
133 | if (i >= MRVDRV_MAX_REGION_CODE) { | ||
134 | lbs_pr_debug(1, "region Code not identified\n"); | ||
135 | LEAVE(); | ||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) { | ||
140 | LEAVE(); | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * @brief Get/Set Firmware wakeup method | ||
149 | * | ||
150 | * @param priv A pointer to wlan_private structure | ||
151 | * @param wrq A pointer to user data | ||
152 | * @return 0--success, otherwise fail | ||
153 | */ | ||
154 | static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq) | ||
155 | { | ||
156 | wlan_adapter *adapter = priv->adapter; | ||
157 | int data; | ||
158 | ENTER(); | ||
159 | |||
160 | if ((int)wrq->u.data.length == 0) { | ||
161 | if (copy_to_user | ||
162 | (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) { | ||
163 | lbs_pr_alert("copy_to_user failed!\n"); | ||
164 | return -EFAULT; | ||
165 | } | ||
166 | } else { | ||
167 | if ((int)wrq->u.data.length > 1) { | ||
168 | lbs_pr_alert("ioctl too many args!\n"); | ||
169 | return -EFAULT; | ||
170 | } | ||
171 | if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { | ||
172 | lbs_pr_alert("Copy from user failed\n"); | ||
173 | return -EFAULT; | ||
174 | } | ||
175 | |||
176 | adapter->pkttxctrl = (u32) data; | ||
177 | } | ||
178 | |||
179 | wrq->u.data.length = 1; | ||
180 | |||
181 | LEAVE(); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * @brief Get/Set NULL Package generation interval | ||
187 | * | ||
188 | * @param priv A pointer to wlan_private structure | ||
189 | * @param wrq A pointer to user data | ||
190 | * @return 0--success, otherwise fail | ||
191 | */ | ||
192 | static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq) | ||
193 | { | ||
194 | wlan_adapter *adapter = priv->adapter; | ||
195 | int data; | ||
196 | ENTER(); | ||
197 | |||
198 | if ((int)wrq->u.data.length == 0) { | ||
199 | data = adapter->nullpktinterval; | ||
200 | |||
201 | if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { | ||
202 | lbs_pr_alert( "copy_to_user failed!\n"); | ||
203 | return -EFAULT; | ||
204 | } | ||
205 | } else { | ||
206 | if ((int)wrq->u.data.length > 1) { | ||
207 | lbs_pr_alert( "ioctl too many args!\n"); | ||
208 | return -EFAULT; | ||
209 | } | ||
210 | if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { | ||
211 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
212 | return -EFAULT; | ||
213 | } | ||
214 | |||
215 | adapter->nullpktinterval = data; | ||
216 | } | ||
217 | |||
218 | wrq->u.data.length = 1; | ||
219 | |||
220 | LEAVE(); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq) | ||
225 | { | ||
226 | wlan_adapter *adapter = priv->adapter; | ||
227 | int data[2]; | ||
228 | ENTER(); | ||
229 | data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; | ||
230 | data[1] = adapter->rxpd_rate; | ||
231 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { | ||
232 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
233 | return -EFAULT; | ||
234 | } | ||
235 | wrq->u.data.length = 2; | ||
236 | LEAVE(); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq) | ||
241 | { | ||
242 | int ret = 0; | ||
243 | wlan_adapter *adapter = priv->adapter; | ||
244 | int data[4]; | ||
245 | |||
246 | ENTER(); | ||
247 | memset(data, 0, sizeof(data)); | ||
248 | if (wrq->u.data.length) { | ||
249 | if (copy_from_user(data, wrq->u.data.pointer, | ||
250 | min_t(size_t, wrq->u.data.length, 4) * sizeof(int))) | ||
251 | return -EFAULT; | ||
252 | } | ||
253 | if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) { | ||
254 | if (adapter->connect_status == libertas_connected) { | ||
255 | ret = libertas_prepare_and_send_command(priv, | ||
256 | cmd_802_11_rssi, | ||
257 | 0, | ||
258 | cmd_option_waitforrsp, | ||
259 | 0, NULL); | ||
260 | |||
261 | if (ret) { | ||
262 | LEAVE(); | ||
263 | return ret; | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | if (wrq->u.data.length == 0) { | ||
269 | data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; | ||
270 | data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; | ||
271 | data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; | ||
272 | data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | ||
273 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) | ||
274 | return -EFAULT; | ||
275 | wrq->u.data.length = 4; | ||
276 | } else if (data[0] == 0) { | ||
277 | data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; | ||
278 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) | ||
279 | return -EFAULT; | ||
280 | wrq->u.data.length = 1; | ||
281 | } else if (data[0] == 1) { | ||
282 | data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; | ||
283 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) | ||
284 | return -EFAULT; | ||
285 | wrq->u.data.length = 1; | ||
286 | } else if (data[0] == 2) { | ||
287 | data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; | ||
288 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) | ||
289 | return -EFAULT; | ||
290 | wrq->u.data.length = 1; | ||
291 | } else if (data[0] == 3) { | ||
292 | data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | ||
293 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) | ||
294 | return -EFAULT; | ||
295 | wrq->u.data.length = 1; | ||
296 | } else | ||
297 | return -ENOTSUPP; | ||
298 | |||
299 | LEAVE(); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq) | ||
304 | { | ||
305 | int data; | ||
306 | wlan_adapter *adapter = priv->adapter; | ||
307 | |||
308 | if (wrq->u.data.length > 0) { | ||
309 | if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) | ||
310 | return -EFAULT; | ||
311 | |||
312 | lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data); | ||
313 | if ((data > MRVDRV_MAX_BEACON_INTERVAL) | ||
314 | || (data < MRVDRV_MIN_BEACON_INTERVAL)) | ||
315 | return -ENOTSUPP; | ||
316 | adapter->beaconperiod = data; | ||
317 | } | ||
318 | data = adapter->beaconperiod; | ||
319 | if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) | ||
320 | return -EFAULT; | ||
321 | |||
322 | wrq->u.data.length = 1; | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq) | ||
328 | { | ||
329 | int ret = 0; | ||
330 | wlan_adapter *adapter = priv->adapter; | ||
331 | int temp; | ||
332 | int data = 0; | ||
333 | int *val; | ||
334 | |||
335 | ENTER(); | ||
336 | data = SUBCMD_DATA(wrq); | ||
337 | if ((data == 0) || (data == 1)) { | ||
338 | ret = libertas_prepare_and_send_command(priv, | ||
339 | cmd_802_11_rssi, | ||
340 | 0, cmd_option_waitforrsp, | ||
341 | 0, NULL); | ||
342 | if (ret) { | ||
343 | LEAVE(); | ||
344 | return ret; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | switch (data) { | ||
349 | case 0: | ||
350 | |||
351 | temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], | ||
352 | adapter->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
353 | break; | ||
354 | case 1: | ||
355 | temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG], | ||
356 | adapter->NF[TYPE_BEACON][TYPE_AVG]); | ||
357 | break; | ||
358 | case 2: | ||
359 | temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], | ||
360 | adapter->NF[TYPE_RXPD][TYPE_NOAVG]); | ||
361 | break; | ||
362 | case 3: | ||
363 | temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, | ||
364 | adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); | ||
365 | break; | ||
366 | default: | ||
367 | return -ENOTSUPP; | ||
368 | } | ||
369 | val = (int *)wrq->u.name; | ||
370 | *val = temp; | ||
371 | |||
372 | LEAVE(); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq) | ||
377 | { | ||
378 | int ret = 0; | ||
379 | wlan_adapter *adapter = priv->adapter; | ||
380 | int temp; | ||
381 | int data = 0; | ||
382 | int *val; | ||
383 | |||
384 | data = SUBCMD_DATA(wrq); | ||
385 | if ((data == 0) || (data == 1)) { | ||
386 | ret = libertas_prepare_and_send_command(priv, | ||
387 | cmd_802_11_rssi, | ||
388 | 0, cmd_option_waitforrsp, | ||
389 | 0, NULL); | ||
390 | |||
391 | if (ret) { | ||
392 | LEAVE(); | ||
393 | return ret; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | switch (data) { | ||
398 | case 0: | ||
399 | temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG]; | ||
400 | break; | ||
401 | case 1: | ||
402 | temp = adapter->NF[TYPE_BEACON][TYPE_AVG]; | ||
403 | break; | ||
404 | case 2: | ||
405 | temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG]; | ||
406 | break; | ||
407 | case 3: | ||
408 | temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | ||
409 | break; | ||
410 | default: | ||
411 | return -ENOTSUPP; | ||
412 | } | ||
413 | |||
414 | temp = CAL_NF(temp); | ||
415 | |||
416 | lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp); | ||
417 | val = (int *)wrq->u.name; | ||
418 | *val = temp; | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req) | ||
423 | { | ||
424 | wlan_adapter *adapter = priv->adapter; | ||
425 | int *pdata; | ||
426 | struct iwreq *wrq = (struct iwreq *)req; | ||
427 | int ret = 0; | ||
428 | adapter->txrate = 0; | ||
429 | lbs_pr_debug(1, "wlan_get_txrate_ioctl\n"); | ||
430 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query, | ||
431 | cmd_act_get, cmd_option_waitforrsp, | ||
432 | 0, NULL); | ||
433 | if (ret) | ||
434 | return ret; | ||
435 | |||
436 | pdata = (int *)wrq->u.name; | ||
437 | *pdata = (int)adapter->txrate; | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
442 | { | ||
443 | char status[64]; | ||
444 | wlan_adapter *adapter = priv->adapter; | ||
445 | |||
446 | memset(status, 0, sizeof(status)); | ||
447 | |||
448 | switch (adapter->inframode) { | ||
449 | case wlan802_11ibss: | ||
450 | if (adapter->connect_status == libertas_connected) { | ||
451 | if (adapter->adhoccreate) | ||
452 | memcpy(&status, "AdhocStarted", sizeof(status)); | ||
453 | else | ||
454 | memcpy(&status, "AdhocJoined", sizeof(status)); | ||
455 | } else { | ||
456 | memcpy(&status, "AdhocIdle", sizeof(status)); | ||
457 | } | ||
458 | break; | ||
459 | case wlan802_11infrastructure: | ||
460 | memcpy(&status, "Inframode", sizeof(status)); | ||
461 | break; | ||
462 | default: | ||
463 | memcpy(&status, "AutoUnknownmode", sizeof(status)); | ||
464 | break; | ||
465 | } | ||
466 | |||
467 | lbs_pr_debug(1, "status = %s\n", status); | ||
468 | wrq->u.data.length = strlen(status) + 1; | ||
469 | |||
470 | if (wrq->u.data.pointer) { | ||
471 | if (copy_to_user(wrq->u.data.pointer, | ||
472 | &status, wrq->u.data.length)) | ||
473 | return -EFAULT; | ||
474 | } | ||
475 | |||
476 | LEAVE(); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * @brief Set/Get WPA IE | ||
482 | * @param priv A pointer to wlan_private structure | ||
483 | * @param req A pointer to ifreq structure | ||
484 | * @return 0 --success, otherwise fail | ||
485 | */ | ||
486 | static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req) | ||
487 | { | ||
488 | struct iwreq *wrq = (struct iwreq *)req; | ||
489 | wlan_adapter *adapter = priv->adapter; | ||
490 | int ret = 0; | ||
491 | |||
492 | ENTER(); | ||
493 | |||
494 | if (wrq->u.data.length) { | ||
495 | if (wrq->u.data.length > sizeof(adapter->wpa_ie)) { | ||
496 | lbs_pr_debug(1, "failed to copy WPA IE, too big \n"); | ||
497 | return -EFAULT; | ||
498 | } | ||
499 | if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer, | ||
500 | wrq->u.data.length)) { | ||
501 | lbs_pr_debug(1, "failed to copy WPA IE \n"); | ||
502 | return -EFAULT; | ||
503 | } | ||
504 | adapter->wpa_ie_len = wrq->u.data.length; | ||
505 | lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len, | ||
506 | adapter->wpa_ie[0]); | ||
507 | lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len); | ||
508 | if (adapter->wpa_ie[0] == WPA_IE) | ||
509 | adapter->secinfo.WPAenabled = 1; | ||
510 | else if (adapter->wpa_ie[0] == WPA2_IE) | ||
511 | adapter->secinfo.WPA2enabled = 1; | ||
512 | else { | ||
513 | adapter->secinfo.WPAenabled = 0; | ||
514 | adapter->secinfo.WPA2enabled = 0; | ||
515 | } | ||
516 | } else { | ||
517 | memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie)); | ||
518 | adapter->wpa_ie_len = wrq->u.data.length; | ||
519 | lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n", | ||
520 | adapter->wpa_ie_len, adapter->wpa_ie[0]); | ||
521 | adapter->secinfo.WPAenabled = 0; | ||
522 | adapter->secinfo.WPA2enabled = 0; | ||
523 | } | ||
524 | |||
525 | // enable/disable RSN in firmware if WPA is enabled/disabled | ||
526 | // depending on variable adapter->secinfo.WPAenabled is set or not | ||
527 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn, | ||
528 | cmd_act_set, cmd_option_waitforrsp, | ||
529 | 0, NULL); | ||
530 | |||
531 | LEAVE(); | ||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | /** | ||
536 | * @brief Set Auto prescan | ||
537 | * @param priv A pointer to wlan_private structure | ||
538 | * @param wrq A pointer to iwreq structure | ||
539 | * @return 0 --success, otherwise fail | ||
540 | */ | ||
541 | static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
542 | { | ||
543 | int data; | ||
544 | wlan_adapter *adapter = priv->adapter; | ||
545 | int *val; | ||
546 | |||
547 | data = SUBCMD_DATA(wrq); | ||
548 | lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data); | ||
549 | adapter->prescan = data; | ||
550 | |||
551 | val = (int *)wrq->u.name; | ||
552 | *val = data; | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req) | ||
557 | { | ||
558 | struct iwreq *wrq = (struct iwreq *)req; | ||
559 | u32 mdtim; | ||
560 | int idata; | ||
561 | int ret = -EINVAL; | ||
562 | |||
563 | ENTER(); | ||
564 | |||
565 | idata = SUBCMD_DATA(wrq); | ||
566 | mdtim = (u32) idata; | ||
567 | if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) | ||
568 | && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM)) | ||
569 | || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) { | ||
570 | priv->adapter->multipledtim = mdtim; | ||
571 | ret = 0; | ||
572 | } | ||
573 | if (ret) | ||
574 | lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n"); | ||
575 | |||
576 | LEAVE(); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * @brief Set authentication mode | ||
582 | * @param priv A pointer to wlan_private structure | ||
583 | * @param req A pointer to ifreq structure | ||
584 | * @return 0 --success, otherwise fail | ||
585 | */ | ||
586 | static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req) | ||
587 | { | ||
588 | int alg; | ||
589 | struct iwreq *wrq = (struct iwreq *)req; | ||
590 | wlan_adapter *adapter = priv->adapter; | ||
591 | |||
592 | if (wrq->u.data.flags == 0) { | ||
593 | //from iwpriv subcmd | ||
594 | alg = SUBCMD_DATA(wrq); | ||
595 | } else { | ||
596 | //from wpa_supplicant subcmd | ||
597 | if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) { | ||
598 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
599 | return -EFAULT; | ||
600 | } | ||
601 | } | ||
602 | |||
603 | lbs_pr_debug(1, "auth alg is %#x\n", alg); | ||
604 | |||
605 | switch (alg) { | ||
606 | case AUTH_ALG_SHARED_KEY: | ||
607 | adapter->secinfo.authmode = wlan802_11authmodeshared; | ||
608 | break; | ||
609 | case AUTH_ALG_NETWORK_EAP: | ||
610 | adapter->secinfo.authmode = | ||
611 | wlan802_11authmodenetworkEAP; | ||
612 | break; | ||
613 | case AUTH_ALG_OPEN_SYSTEM: | ||
614 | default: | ||
615 | adapter->secinfo.authmode = wlan802_11authmodeopen; | ||
616 | break; | ||
617 | } | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | /** | ||
622 | * @brief Set 802.1x authentication mode | ||
623 | * @param priv A pointer to wlan_private structure | ||
624 | * @param req A pointer to ifreq structure | ||
625 | * @return 0 --success, otherwise fail | ||
626 | */ | ||
627 | static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req) | ||
628 | { | ||
629 | int alg; | ||
630 | struct iwreq *wrq = (struct iwreq *)req; | ||
631 | |||
632 | if (wrq->u.data.flags == 0) { | ||
633 | //from iwpriv subcmd | ||
634 | alg = SUBCMD_DATA(wrq); | ||
635 | } else { | ||
636 | //from wpa_supplicant subcmd | ||
637 | if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) { | ||
638 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
639 | return -EFAULT; | ||
640 | } | ||
641 | } | ||
642 | lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg); | ||
643 | priv->adapter->secinfo.auth1xalg = alg; | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req) | ||
648 | { | ||
649 | int mode; | ||
650 | struct iwreq *wrq = (struct iwreq *)req; | ||
651 | |||
652 | ENTER(); | ||
653 | |||
654 | if (wrq->u.data.flags == 0) { | ||
655 | //from iwpriv subcmd | ||
656 | mode = SUBCMD_DATA(wrq); | ||
657 | } else { | ||
658 | //from wpa_supplicant subcmd | ||
659 | if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) { | ||
660 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
661 | return -EFAULT; | ||
662 | } | ||
663 | } | ||
664 | lbs_pr_debug(1, "encryption mode is %#x\n", mode); | ||
665 | priv->adapter->secinfo.Encryptionmode = mode; | ||
666 | |||
667 | LEAVE(); | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static void adjust_mtu(wlan_private * priv) | ||
672 | { | ||
673 | int mtu_increment = 0; | ||
674 | |||
675 | if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) | ||
676 | mtu_increment += sizeof(struct ieee80211_hdr_4addr); | ||
677 | |||
678 | if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) | ||
679 | mtu_increment += max(sizeof(struct tx_radiotap_hdr), | ||
680 | sizeof(struct rx_radiotap_hdr)); | ||
681 | priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN | ||
682 | - sizeof(struct ethhdr) | ||
683 | + mtu_increment; | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * @brief Set Link-Layer Layer mode | ||
688 | * @param priv A pointer to wlan_private structure | ||
689 | * @param req A pointer to ifreq structure | ||
690 | * @return 0 --success, otherwise fail | ||
691 | */ | ||
692 | static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req) | ||
693 | { | ||
694 | int mode; | ||
695 | |||
696 | mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; | ||
697 | |||
698 | switch (mode) { | ||
699 | case WLAN_LINKMODE_802_3: | ||
700 | priv->adapter->linkmode = mode; | ||
701 | break; | ||
702 | case WLAN_LINKMODE_802_11: | ||
703 | priv->adapter->linkmode = mode; | ||
704 | break; | ||
705 | default: | ||
706 | lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n", | ||
707 | mode); | ||
708 | return -EINVAL; | ||
709 | break; | ||
710 | } | ||
711 | lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode); | ||
712 | |||
713 | adjust_mtu(priv); | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | /** | ||
719 | * @brief Set Radio header mode | ||
720 | * @param priv A pointer to wlan_private structure | ||
721 | * @param req A pointer to ifreq structure | ||
722 | * @return 0 --success, otherwise fail | ||
723 | */ | ||
724 | static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req) | ||
725 | { | ||
726 | int mode; | ||
727 | |||
728 | mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; | ||
729 | |||
730 | switch (mode) { | ||
731 | case WLAN_RADIOMODE_NONE: | ||
732 | priv->adapter->radiomode = mode; | ||
733 | break; | ||
734 | case WLAN_RADIOMODE_RADIOTAP: | ||
735 | priv->adapter->radiomode = mode; | ||
736 | break; | ||
737 | default: | ||
738 | lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n", | ||
739 | mode); | ||
740 | return -EINVAL; | ||
741 | } | ||
742 | lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode); | ||
743 | |||
744 | adjust_mtu(priv); | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | /** | ||
749 | * @brief Set Debug header mode | ||
750 | * @param priv A pointer to wlan_private structure | ||
751 | * @param req A pointer to ifreq structure | ||
752 | * @return 0 --success, otherwise fail | ||
753 | */ | ||
754 | static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req) | ||
755 | { | ||
756 | priv->adapter->debugmode = (int)((struct ifreq *) | ||
757 | ((u8 *) req + 4))->ifr_data; | ||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, | ||
762 | struct ifreq *req) | ||
763 | { | ||
764 | int len; | ||
765 | char buf[8]; | ||
766 | struct iwreq *wrq = (struct iwreq *)req; | ||
767 | |||
768 | lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n"); | ||
769 | len = getrxantenna(priv, buf); | ||
770 | |||
771 | wrq->u.data.length = len; | ||
772 | if (wrq->u.data.pointer) { | ||
773 | if (copy_to_user(wrq->u.data.pointer, &buf, len)) { | ||
774 | lbs_pr_debug(1, "CopyToUser failed\n"); | ||
775 | return -EFAULT; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, | ||
783 | struct ifreq *req) | ||
784 | { | ||
785 | int len; | ||
786 | char buf[8]; | ||
787 | struct iwreq *wrq = (struct iwreq *)req; | ||
788 | |||
789 | lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n"); | ||
790 | len = gettxantenna(priv, buf); | ||
791 | |||
792 | wrq->u.data.length = len; | ||
793 | if (wrq->u.data.pointer) { | ||
794 | if (copy_to_user(wrq->u.data.pointer, &buf, len)) { | ||
795 | lbs_pr_debug(1, "CopyToUser failed\n"); | ||
796 | return -EFAULT; | ||
797 | } | ||
798 | } | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | /** | ||
803 | * @brief Get the MAC TSF value from the firmware | ||
804 | * | ||
805 | * @param priv A pointer to wlan_private structure | ||
806 | * @param wrq A pointer to iwreq structure containing buffer | ||
807 | * space to store a TSF value retrieved from the firmware | ||
808 | * | ||
809 | * @return 0 if successful; IOCTL error code otherwise | ||
810 | */ | ||
811 | static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
812 | { | ||
813 | u64 tsfval; | ||
814 | int ret; | ||
815 | |||
816 | ret = libertas_prepare_and_send_command(priv, | ||
817 | cmd_get_tsf, | ||
818 | 0, cmd_option_waitforrsp, 0, &tsfval); | ||
819 | |||
820 | lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval); | ||
821 | |||
822 | if (ret != 0) { | ||
823 | lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n"); | ||
824 | ret = -EFAULT; | ||
825 | } else { | ||
826 | if (copy_to_user(wrq->u.data.pointer, | ||
827 | &tsfval, | ||
828 | min_t(size_t, wrq->u.data.length, | ||
829 | sizeof(tsfval))) != 0) { | ||
830 | |||
831 | lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n"); | ||
832 | ret = -EFAULT; | ||
833 | } else { | ||
834 | ret = 0; | ||
835 | } | ||
836 | } | ||
837 | return ret; | ||
838 | } | ||
839 | |||
840 | /** | ||
841 | * @brief Get/Set adapt rate | ||
842 | * @param priv A pointer to wlan_private structure | ||
843 | * @param wrq A pointer to iwreq structure | ||
844 | * @return 0 --success, otherwise fail | ||
845 | */ | ||
846 | static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq) | ||
847 | { | ||
848 | int ret; | ||
849 | wlan_adapter *adapter = priv->adapter; | ||
850 | int data[2]; | ||
851 | |||
852 | memset(data, 0, sizeof(data)); | ||
853 | if (!wrq->u.data.length) { | ||
854 | lbs_pr_debug(1, "Get ADAPT RATE SET\n"); | ||
855 | ret = libertas_prepare_and_send_command(priv, | ||
856 | cmd_802_11_rate_adapt_rateset, | ||
857 | cmd_act_get, | ||
858 | cmd_option_waitforrsp, 0, NULL); | ||
859 | data[0] = adapter->enablehwauto; | ||
860 | data[1] = adapter->ratebitmap; | ||
861 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { | ||
862 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
863 | return -EFAULT; | ||
864 | } | ||
865 | #define GET_TWO_INT 2 | ||
866 | wrq->u.data.length = GET_TWO_INT; | ||
867 | } else { | ||
868 | lbs_pr_debug(1, "Set ADAPT RATE SET\n"); | ||
869 | if (wrq->u.data.length > 2) | ||
870 | return -EINVAL; | ||
871 | if (copy_from_user | ||
872 | (data, wrq->u.data.pointer, | ||
873 | sizeof(int) * wrq->u.data.length)) { | ||
874 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
875 | return -EFAULT; | ||
876 | } | ||
877 | |||
878 | adapter->enablehwauto = data[0]; | ||
879 | adapter->ratebitmap = data[1]; | ||
880 | ret = libertas_prepare_and_send_command(priv, | ||
881 | cmd_802_11_rate_adapt_rateset, | ||
882 | cmd_act_set, | ||
883 | cmd_option_waitforrsp, 0, NULL); | ||
884 | } | ||
885 | return ret; | ||
886 | } | ||
887 | |||
888 | /** | ||
889 | * @brief Get/Set inactivity timeout | ||
890 | * @param priv A pointer to wlan_private structure | ||
891 | * @param wrq A pointer to iwreq structure | ||
892 | * @return 0 --success, otherwise fail | ||
893 | */ | ||
894 | static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq) | ||
895 | { | ||
896 | int ret; | ||
897 | int data = 0; | ||
898 | u16 timeout = 0; | ||
899 | |||
900 | ENTER(); | ||
901 | if (wrq->u.data.length > 1) | ||
902 | return -ENOTSUPP; | ||
903 | |||
904 | if (wrq->u.data.length == 0) { | ||
905 | /* Get */ | ||
906 | ret = libertas_prepare_and_send_command(priv, | ||
907 | cmd_802_11_inactivity_timeout, | ||
908 | cmd_act_get, | ||
909 | cmd_option_waitforrsp, 0, | ||
910 | &timeout); | ||
911 | data = timeout; | ||
912 | if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { | ||
913 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
914 | return -EFAULT; | ||
915 | } | ||
916 | } else { | ||
917 | /* Set */ | ||
918 | if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { | ||
919 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
920 | return -EFAULT; | ||
921 | } | ||
922 | |||
923 | timeout = data; | ||
924 | ret = libertas_prepare_and_send_command(priv, | ||
925 | cmd_802_11_inactivity_timeout, | ||
926 | cmd_act_set, | ||
927 | cmd_option_waitforrsp, 0, | ||
928 | &timeout); | ||
929 | } | ||
930 | |||
931 | wrq->u.data.length = 1; | ||
932 | |||
933 | LEAVE(); | ||
934 | return ret; | ||
935 | } | ||
936 | |||
937 | static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
938 | { | ||
939 | int ret; | ||
940 | char buf[GETLOG_BUFSIZE - 1]; | ||
941 | wlan_adapter *adapter = priv->adapter; | ||
942 | |||
943 | lbs_pr_debug(1, " GET STATS\n"); | ||
944 | |||
945 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log, | ||
946 | 0, cmd_option_waitforrsp, 0, NULL); | ||
947 | |||
948 | if (ret) { | ||
949 | return ret; | ||
950 | } | ||
951 | |||
952 | if (wrq->u.data.pointer) { | ||
953 | sprintf(buf, "\n mcasttxframe %u failed %u retry %u " | ||
954 | "multiretry %u framedup %u " | ||
955 | "rtssuccess %u rtsfailure %u ackfailure %u\n" | ||
956 | "rxfrag %u mcastrxframe %u fcserror %u " | ||
957 | "txframe %u wepundecryptable %u ", | ||
958 | adapter->logmsg.mcasttxframe, | ||
959 | adapter->logmsg.failed, | ||
960 | adapter->logmsg.retry, | ||
961 | adapter->logmsg.multiretry, | ||
962 | adapter->logmsg.framedup, | ||
963 | adapter->logmsg.rtssuccess, | ||
964 | adapter->logmsg.rtsfailure, | ||
965 | adapter->logmsg.ackfailure, | ||
966 | adapter->logmsg.rxfrag, | ||
967 | adapter->logmsg.mcastrxframe, | ||
968 | adapter->logmsg.fcserror, | ||
969 | adapter->logmsg.txframe, | ||
970 | adapter->logmsg.wepundecryptable); | ||
971 | wrq->u.data.length = strlen(buf) + 1; | ||
972 | if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) { | ||
973 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
974 | return -EFAULT; | ||
975 | } | ||
976 | } | ||
977 | |||
978 | return 0; | ||
979 | } | ||
980 | |||
981 | static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
982 | { | ||
983 | u8 buf[12]; | ||
984 | u8 *option[] = { "active", "passive", "get", }; | ||
985 | int i, max_options = (sizeof(option) / sizeof(option[0])); | ||
986 | int ret = 0; | ||
987 | wlan_adapter *adapter = priv->adapter; | ||
988 | |||
989 | if (priv->adapter->enable11d) { | ||
990 | lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n"); | ||
991 | return -EFAULT; | ||
992 | } | ||
993 | |||
994 | memset(buf, 0, sizeof(buf)); | ||
995 | |||
996 | if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), | ||
997 | wrq->u.data.length))) | ||
998 | return -EFAULT; | ||
999 | |||
1000 | lbs_pr_debug(1, "Scan type Option = %s\n", buf); | ||
1001 | |||
1002 | buf[sizeof(buf) - 1] = '\0'; | ||
1003 | |||
1004 | for (i = 0; i < max_options; i++) { | ||
1005 | if (!strcmp(buf, option[i])) | ||
1006 | break; | ||
1007 | } | ||
1008 | |||
1009 | switch (i) { | ||
1010 | case 0: | ||
1011 | adapter->scantype = cmd_scan_type_active; | ||
1012 | break; | ||
1013 | case 1: | ||
1014 | adapter->scantype = cmd_scan_type_passive; | ||
1015 | break; | ||
1016 | case 2: | ||
1017 | wrq->u.data.length = strlen(option[adapter->scantype]) + 1; | ||
1018 | |||
1019 | if (copy_to_user(wrq->u.data.pointer, | ||
1020 | option[adapter->scantype], | ||
1021 | wrq->u.data.length)) { | ||
1022 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
1023 | ret = -EFAULT; | ||
1024 | } | ||
1025 | |||
1026 | break; | ||
1027 | default: | ||
1028 | lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n"); | ||
1029 | ret = -EINVAL; | ||
1030 | break; | ||
1031 | } | ||
1032 | |||
1033 | return ret; | ||
1034 | } | ||
1035 | |||
1036 | static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
1037 | { | ||
1038 | wlan_adapter *adapter = priv->adapter; | ||
1039 | u8 buf[12]; | ||
1040 | u8 *option[] = { "bss", "ibss", "any", "get" }; | ||
1041 | int i, max_options = (sizeof(option) / sizeof(option[0])); | ||
1042 | int ret = 0; | ||
1043 | |||
1044 | ENTER(); | ||
1045 | |||
1046 | memset(buf, 0, sizeof(buf)); | ||
1047 | |||
1048 | if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), | ||
1049 | wrq->u.data.length))) { | ||
1050 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
1051 | return -EFAULT; | ||
1052 | } | ||
1053 | |||
1054 | lbs_pr_debug(1, "Scan mode Option = %s\n", buf); | ||
1055 | |||
1056 | buf[sizeof(buf) - 1] = '\0'; | ||
1057 | |||
1058 | for (i = 0; i < max_options; i++) { | ||
1059 | if (!strcmp(buf, option[i])) | ||
1060 | break; | ||
1061 | } | ||
1062 | |||
1063 | switch (i) { | ||
1064 | |||
1065 | case 0: | ||
1066 | adapter->scanmode = cmd_bss_type_bss; | ||
1067 | break; | ||
1068 | case 1: | ||
1069 | adapter->scanmode = cmd_bss_type_ibss; | ||
1070 | break; | ||
1071 | case 2: | ||
1072 | adapter->scanmode = cmd_bss_type_any; | ||
1073 | break; | ||
1074 | case 3: | ||
1075 | |||
1076 | wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1; | ||
1077 | |||
1078 | lbs_pr_debug(1, "Get Scan mode Option = %s\n", | ||
1079 | option[adapter->scanmode - 1]); | ||
1080 | |||
1081 | lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length); | ||
1082 | |||
1083 | if (copy_to_user(wrq->u.data.pointer, | ||
1084 | option[adapter->scanmode - 1], | ||
1085 | wrq->u.data.length)) { | ||
1086 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
1087 | ret = -EFAULT; | ||
1088 | } | ||
1089 | lbs_pr_debug(1, "GET Scan type Option after copy = %s\n", | ||
1090 | (char *)wrq->u.data.pointer); | ||
1091 | |||
1092 | break; | ||
1093 | |||
1094 | default: | ||
1095 | lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n"); | ||
1096 | ret = -EINVAL; | ||
1097 | break; | ||
1098 | } | ||
1099 | |||
1100 | LEAVE(); | ||
1101 | return ret; | ||
1102 | } | ||
1103 | |||
1104 | /** | ||
1105 | * @brief Get/Set Adhoc G Rate | ||
1106 | * | ||
1107 | * @param priv A pointer to wlan_private structure | ||
1108 | * @param wrq A pointer to user data | ||
1109 | * @return 0--success, otherwise fail | ||
1110 | */ | ||
1111 | static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
1112 | { | ||
1113 | wlan_adapter *adapter = priv->adapter; | ||
1114 | int data, data1; | ||
1115 | int *val; | ||
1116 | |||
1117 | ENTER(); | ||
1118 | |||
1119 | data1 = SUBCMD_DATA(wrq); | ||
1120 | switch (data1) { | ||
1121 | case 0: | ||
1122 | adapter->adhoc_grate_enabled = 0; | ||
1123 | break; | ||
1124 | case 1: | ||
1125 | adapter->adhoc_grate_enabled = 1; | ||
1126 | break; | ||
1127 | case 2: | ||
1128 | break; | ||
1129 | default: | ||
1130 | return -EINVAL; | ||
1131 | } | ||
1132 | data = adapter->adhoc_grate_enabled; | ||
1133 | val = (int *)wrq->u.name; | ||
1134 | *val = data; | ||
1135 | LEAVE(); | ||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | static inline int hex2int(char c) | ||
1140 | { | ||
1141 | if (c >= '0' && c <= '9') | ||
1142 | return (c - '0'); | ||
1143 | if (c >= 'a' && c <= 'f') | ||
1144 | return (c - 'a' + 10); | ||
1145 | if (c >= 'A' && c <= 'F') | ||
1146 | return (c - 'A' + 10); | ||
1147 | return -1; | ||
1148 | } | ||
1149 | |||
1150 | /* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx") | ||
1151 | into binary format (6 bytes). | ||
1152 | |||
1153 | This function expects that each byte is represented with 2 characters | ||
1154 | (e.g., 11:2:11:11:11:11 is invalid) | ||
1155 | |||
1156 | */ | ||
1157 | static char *eth_str2addr(char *ethstr, u8 * addr) | ||
1158 | { | ||
1159 | int i, val, val2; | ||
1160 | char *pos = ethstr; | ||
1161 | |||
1162 | /* get rid of initial blanks */ | ||
1163 | while (*pos == ' ' || *pos == '\t') | ||
1164 | ++pos; | ||
1165 | |||
1166 | for (i = 0; i < 6; i++) { | ||
1167 | val = hex2int(*pos++); | ||
1168 | if (val < 0) | ||
1169 | return NULL; | ||
1170 | val2 = hex2int(*pos++); | ||
1171 | if (val2 < 0) | ||
1172 | return NULL; | ||
1173 | addr[i] = (val * 16 + val2) & 0xff; | ||
1174 | |||
1175 | if (i < 5 && *pos++ != ':') | ||
1176 | return NULL; | ||
1177 | } | ||
1178 | return pos; | ||
1179 | } | ||
1180 | |||
1181 | /* this writes xx:xx:xx:xx:xx:xx into ethstr | ||
1182 | (ethstr must have space for 18 chars) */ | ||
1183 | static int eth_addr2str(u8 * addr, char *ethstr) | ||
1184 | { | ||
1185 | int i; | ||
1186 | char *pos = ethstr; | ||
1187 | |||
1188 | for (i = 0; i < 6; i++) { | ||
1189 | sprintf(pos, "%02x", addr[i] & 0xff); | ||
1190 | pos += 2; | ||
1191 | if (i < 5) | ||
1192 | *pos++ = ':'; | ||
1193 | } | ||
1194 | return 17; | ||
1195 | } | ||
1196 | |||
1197 | /** | ||
1198 | * @brief Add an entry to the BT table | ||
1199 | * @param priv A pointer to wlan_private structure | ||
1200 | * @param req A pointer to ifreq structure | ||
1201 | * @return 0 --success, otherwise fail | ||
1202 | */ | ||
1203 | static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req) | ||
1204 | { | ||
1205 | struct iwreq *wrq = (struct iwreq *)req; | ||
1206 | char ethaddrs_str[18]; | ||
1207 | char *pos; | ||
1208 | u8 ethaddr[ETH_ALEN]; | ||
1209 | |||
1210 | ENTER(); | ||
1211 | if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, | ||
1212 | sizeof(ethaddrs_str))) | ||
1213 | return -EFAULT; | ||
1214 | |||
1215 | if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { | ||
1216 | lbs_pr_info("BT_ADD: Invalid MAC address\n"); | ||
1217 | return -EINVAL; | ||
1218 | } | ||
1219 | |||
1220 | lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str); | ||
1221 | LEAVE(); | ||
1222 | return (libertas_prepare_and_send_command(priv, cmd_bt_access, | ||
1223 | cmd_act_bt_access_add, | ||
1224 | cmd_option_waitforrsp, 0, ethaddr)); | ||
1225 | } | ||
1226 | |||
1227 | /** | ||
1228 | * @brief Delete an entry from the BT table | ||
1229 | * @param priv A pointer to wlan_private structure | ||
1230 | * @param req A pointer to ifreq structure | ||
1231 | * @return 0 --success, otherwise fail | ||
1232 | */ | ||
1233 | static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req) | ||
1234 | { | ||
1235 | struct iwreq *wrq = (struct iwreq *)req; | ||
1236 | char ethaddrs_str[18]; | ||
1237 | u8 ethaddr[ETH_ALEN]; | ||
1238 | char *pos; | ||
1239 | |||
1240 | ENTER(); | ||
1241 | if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, | ||
1242 | sizeof(ethaddrs_str))) | ||
1243 | return -EFAULT; | ||
1244 | |||
1245 | if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { | ||
1246 | lbs_pr_info("Invalid MAC address\n"); | ||
1247 | return -EINVAL; | ||
1248 | } | ||
1249 | |||
1250 | lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str); | ||
1251 | |||
1252 | return (libertas_prepare_and_send_command(priv, | ||
1253 | cmd_bt_access, | ||
1254 | cmd_act_bt_access_del, | ||
1255 | cmd_option_waitforrsp, 0, ethaddr)); | ||
1256 | LEAVE(); | ||
1257 | return 0; | ||
1258 | } | ||
1259 | |||
1260 | /** | ||
1261 | * @brief Reset all entries from the BT table | ||
1262 | * @param priv A pointer to wlan_private structure | ||
1263 | * @return 0 --success, otherwise fail | ||
1264 | */ | ||
1265 | static int wlan_bt_reset_ioctl(wlan_private * priv) | ||
1266 | { | ||
1267 | ENTER(); | ||
1268 | |||
1269 | lbs_pr_alert( "BT: resetting\n"); | ||
1270 | |||
1271 | return (libertas_prepare_and_send_command(priv, | ||
1272 | cmd_bt_access, | ||
1273 | cmd_act_bt_access_reset, | ||
1274 | cmd_option_waitforrsp, 0, NULL)); | ||
1275 | |||
1276 | LEAVE(); | ||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | /** | ||
1281 | * @brief List an entry from the BT table | ||
1282 | * @param priv A pointer to wlan_private structure | ||
1283 | * @param req A pointer to ifreq structure | ||
1284 | * @return 0 --success, otherwise fail | ||
1285 | */ | ||
1286 | static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req) | ||
1287 | { | ||
1288 | int pos; | ||
1289 | char *addr1; | ||
1290 | struct iwreq *wrq = (struct iwreq *)req; | ||
1291 | /* used to pass id and store the bt entry returned by the FW */ | ||
1292 | union { | ||
1293 | int id; | ||
1294 | char addr1addr2[2 * ETH_ALEN]; | ||
1295 | } param; | ||
1296 | static char outstr[64]; | ||
1297 | char *pbuf = outstr; | ||
1298 | int ret; | ||
1299 | |||
1300 | ENTER(); | ||
1301 | |||
1302 | if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { | ||
1303 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
1304 | return -1; | ||
1305 | } | ||
1306 | param.id = simple_strtoul(outstr, NULL, 10); | ||
1307 | pos = sprintf(pbuf, "%d: ", param.id); | ||
1308 | pbuf += pos; | ||
1309 | |||
1310 | ret = libertas_prepare_and_send_command(priv, cmd_bt_access, | ||
1311 | cmd_act_bt_access_list, | ||
1312 | cmd_option_waitforrsp, 0, | ||
1313 | (char *)¶m); | ||
1314 | |||
1315 | if (ret == 0) { | ||
1316 | addr1 = param.addr1addr2; | ||
1317 | |||
1318 | pos = sprintf(pbuf, "ignoring traffic from "); | ||
1319 | pbuf += pos; | ||
1320 | pos = eth_addr2str(addr1, pbuf); | ||
1321 | pbuf += pos; | ||
1322 | } else { | ||
1323 | sprintf(pbuf, "(null)"); | ||
1324 | pbuf += pos; | ||
1325 | } | ||
1326 | |||
1327 | wrq->u.data.length = strlen(outstr); | ||
1328 | if (copy_to_user(wrq->u.data.pointer, (char *)outstr, | ||
1329 | wrq->u.data.length)) { | ||
1330 | lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n"); | ||
1331 | return -EFAULT; | ||
1332 | } | ||
1333 | |||
1334 | LEAVE(); | ||
1335 | return 0; | ||
1336 | } | ||
1337 | |||
1338 | /** | ||
1339 | * @brief Find the next parameter in an input string | ||
1340 | * @param ptr A pointer to the input parameter string | ||
1341 | * @return A pointer to the next parameter, or 0 if no parameters left. | ||
1342 | */ | ||
1343 | static char * next_param(char * ptr) | ||
1344 | { | ||
1345 | if (!ptr) return NULL; | ||
1346 | while (*ptr == ' ' || *ptr == '\t') ++ptr; | ||
1347 | return (*ptr == '\0') ? NULL : ptr; | ||
1348 | } | ||
1349 | |||
1350 | /** | ||
1351 | * @brief Add an entry to the FWT table | ||
1352 | * @param priv A pointer to wlan_private structure | ||
1353 | * @param req A pointer to ifreq structure | ||
1354 | * @return 0 --success, otherwise fail | ||
1355 | */ | ||
1356 | static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req) | ||
1357 | { | ||
1358 | struct iwreq *wrq = (struct iwreq *)req; | ||
1359 | char in_str[128]; | ||
1360 | static struct cmd_ds_fwt_access fwt_access; | ||
1361 | char *ptr; | ||
1362 | |||
1363 | ENTER(); | ||
1364 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1365 | return -EFAULT; | ||
1366 | |||
1367 | if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { | ||
1368 | lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n"); | ||
1369 | return -EINVAL; | ||
1370 | } | ||
1371 | |||
1372 | if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { | ||
1373 | lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n"); | ||
1374 | return -EINVAL; | ||
1375 | } | ||
1376 | |||
1377 | if ((ptr = next_param(ptr))) | ||
1378 | fwt_access.metric = | ||
1379 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1380 | else | ||
1381 | fwt_access.metric = FWT_DEFAULT_METRIC; | ||
1382 | |||
1383 | if ((ptr = next_param(ptr))) | ||
1384 | fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); | ||
1385 | else | ||
1386 | fwt_access.dir = FWT_DEFAULT_DIR; | ||
1387 | |||
1388 | if ((ptr = next_param(ptr))) | ||
1389 | fwt_access.ssn = | ||
1390 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1391 | else | ||
1392 | fwt_access.ssn = FWT_DEFAULT_SSN; | ||
1393 | |||
1394 | if ((ptr = next_param(ptr))) | ||
1395 | fwt_access.dsn = | ||
1396 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1397 | else | ||
1398 | fwt_access.dsn = FWT_DEFAULT_DSN; | ||
1399 | |||
1400 | if ((ptr = next_param(ptr))) | ||
1401 | fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10); | ||
1402 | else | ||
1403 | fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT; | ||
1404 | |||
1405 | if ((ptr = next_param(ptr))) | ||
1406 | fwt_access.ttl = simple_strtoul(ptr, &ptr, 10); | ||
1407 | else | ||
1408 | fwt_access.ttl = FWT_DEFAULT_TTL; | ||
1409 | |||
1410 | if ((ptr = next_param(ptr))) | ||
1411 | fwt_access.expiration = | ||
1412 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1413 | else | ||
1414 | fwt_access.expiration = FWT_DEFAULT_EXPIRATION; | ||
1415 | |||
1416 | if ((ptr = next_param(ptr))) | ||
1417 | fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10); | ||
1418 | else | ||
1419 | fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE; | ||
1420 | |||
1421 | if ((ptr = next_param(ptr))) | ||
1422 | fwt_access.snr = | ||
1423 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1424 | else | ||
1425 | fwt_access.snr = FWT_DEFAULT_SNR; | ||
1426 | |||
1427 | #ifdef DEBUG | ||
1428 | { | ||
1429 | char ethaddr1_str[18], ethaddr2_str[18]; | ||
1430 | eth_addr2str(fwt_access.da, ethaddr1_str); | ||
1431 | eth_addr2str(fwt_access.ra, ethaddr2_str); | ||
1432 | lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str, | ||
1433 | fwt_access.dir, ethaddr2_str); | ||
1434 | lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n", | ||
1435 | fwt_access.ssn, fwt_access.dsn, fwt_access.metric, | ||
1436 | fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration, | ||
1437 | fwt_access.sleepmode, fwt_access.snr); | ||
1438 | } | ||
1439 | #endif | ||
1440 | |||
1441 | LEAVE(); | ||
1442 | return (libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1443 | cmd_act_fwt_access_add, | ||
1444 | cmd_option_waitforrsp, 0, | ||
1445 | (void *)&fwt_access)); | ||
1446 | } | ||
1447 | |||
1448 | /** | ||
1449 | * @brief Delete an entry from the FWT table | ||
1450 | * @param priv A pointer to wlan_private structure | ||
1451 | * @param req A pointer to ifreq structure | ||
1452 | * @return 0 --success, otherwise fail | ||
1453 | */ | ||
1454 | static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req) | ||
1455 | { | ||
1456 | struct iwreq *wrq = (struct iwreq *)req; | ||
1457 | char in_str[64]; | ||
1458 | static struct cmd_ds_fwt_access fwt_access; | ||
1459 | char *ptr; | ||
1460 | |||
1461 | ENTER(); | ||
1462 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1463 | return -EFAULT; | ||
1464 | |||
1465 | if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { | ||
1466 | lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n"); | ||
1467 | return -EINVAL; | ||
1468 | } | ||
1469 | |||
1470 | if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { | ||
1471 | lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n"); | ||
1472 | return -EINVAL; | ||
1473 | } | ||
1474 | |||
1475 | if ((ptr = next_param(ptr))) | ||
1476 | fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); | ||
1477 | else | ||
1478 | fwt_access.dir = FWT_DEFAULT_DIR; | ||
1479 | |||
1480 | #ifdef DEBUG | ||
1481 | { | ||
1482 | char ethaddr1_str[18], ethaddr2_str[18]; | ||
1483 | lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str); | ||
1484 | eth_addr2str(fwt_access.da, ethaddr1_str); | ||
1485 | eth_addr2str(fwt_access.ra, ethaddr2_str); | ||
1486 | lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str, | ||
1487 | ethaddr2_str, fwt_access.dir); | ||
1488 | } | ||
1489 | #endif | ||
1490 | |||
1491 | LEAVE(); | ||
1492 | return (libertas_prepare_and_send_command(priv, | ||
1493 | cmd_fwt_access, | ||
1494 | cmd_act_fwt_access_del, | ||
1495 | cmd_option_waitforrsp, 0, | ||
1496 | (void *)&fwt_access)); | ||
1497 | } | ||
1498 | |||
1499 | |||
1500 | /** | ||
1501 | * @brief Print route parameters | ||
1502 | * @param fwt_access struct cmd_ds_fwt_access with route info | ||
1503 | * @param buf destination buffer for route info | ||
1504 | */ | ||
1505 | static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf) | ||
1506 | { | ||
1507 | buf += sprintf(buf, " "); | ||
1508 | buf += eth_addr2str(fwt_access.da, buf); | ||
1509 | buf += sprintf(buf, " "); | ||
1510 | buf += eth_addr2str(fwt_access.ra, buf); | ||
1511 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric)); | ||
1512 | buf += sprintf(buf, " %u", fwt_access.dir); | ||
1513 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn)); | ||
1514 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn)); | ||
1515 | buf += sprintf(buf, " %u", fwt_access.hopcount); | ||
1516 | buf += sprintf(buf, " %u", fwt_access.ttl); | ||
1517 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration)); | ||
1518 | buf += sprintf(buf, " %u", fwt_access.sleepmode); | ||
1519 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr)); | ||
1520 | } | ||
1521 | |||
1522 | /** | ||
1523 | * @brief Lookup an entry in the FWT table | ||
1524 | * @param priv A pointer to wlan_private structure | ||
1525 | * @param req A pointer to ifreq structure | ||
1526 | * @return 0 --success, otherwise fail | ||
1527 | */ | ||
1528 | static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req) | ||
1529 | { | ||
1530 | struct iwreq *wrq = (struct iwreq *)req; | ||
1531 | char in_str[64]; | ||
1532 | char *ptr; | ||
1533 | static struct cmd_ds_fwt_access fwt_access; | ||
1534 | static char out_str[128]; | ||
1535 | int ret; | ||
1536 | |||
1537 | ENTER(); | ||
1538 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1539 | return -EFAULT; | ||
1540 | |||
1541 | if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { | ||
1542 | lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n"); | ||
1543 | return -EINVAL; | ||
1544 | } | ||
1545 | |||
1546 | #ifdef DEBUG | ||
1547 | { | ||
1548 | char ethaddr1_str[18]; | ||
1549 | lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str); | ||
1550 | eth_addr2str(fwt_access.da, ethaddr1_str); | ||
1551 | lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str); | ||
1552 | } | ||
1553 | #endif | ||
1554 | |||
1555 | ret = libertas_prepare_and_send_command(priv, | ||
1556 | cmd_fwt_access, | ||
1557 | cmd_act_fwt_access_lookup, | ||
1558 | cmd_option_waitforrsp, 0, | ||
1559 | (void *)&fwt_access); | ||
1560 | |||
1561 | if (ret == 0) | ||
1562 | print_route(fwt_access, out_str); | ||
1563 | else | ||
1564 | sprintf(out_str, "(null)"); | ||
1565 | |||
1566 | wrq->u.data.length = strlen(out_str); | ||
1567 | if (copy_to_user(wrq->u.data.pointer, (char *)out_str, | ||
1568 | wrq->u.data.length)) { | ||
1569 | lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n"); | ||
1570 | return -EFAULT; | ||
1571 | } | ||
1572 | |||
1573 | LEAVE(); | ||
1574 | return 0; | ||
1575 | } | ||
1576 | |||
1577 | /** | ||
1578 | * @brief Reset all entries from the FWT table | ||
1579 | * @param priv A pointer to wlan_private structure | ||
1580 | * @return 0 --success, otherwise fail | ||
1581 | */ | ||
1582 | static int wlan_fwt_reset_ioctl(wlan_private * priv) | ||
1583 | { | ||
1584 | lbs_pr_debug(1, "FWT: resetting\n"); | ||
1585 | |||
1586 | return (libertas_prepare_and_send_command(priv, | ||
1587 | cmd_fwt_access, | ||
1588 | cmd_act_fwt_access_reset, | ||
1589 | cmd_option_waitforrsp, 0, NULL)); | ||
1590 | } | ||
1591 | |||
1592 | /** | ||
1593 | * @brief List an entry from the FWT table | ||
1594 | * @param priv A pointer to wlan_private structure | ||
1595 | * @param req A pointer to ifreq structure | ||
1596 | * @return 0 --success, otherwise fail | ||
1597 | */ | ||
1598 | static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req) | ||
1599 | { | ||
1600 | struct iwreq *wrq = (struct iwreq *)req; | ||
1601 | char in_str[8]; | ||
1602 | static struct cmd_ds_fwt_access fwt_access; | ||
1603 | char *ptr = in_str; | ||
1604 | static char out_str[128]; | ||
1605 | char *pbuf = out_str; | ||
1606 | int ret; | ||
1607 | |||
1608 | ENTER(); | ||
1609 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1610 | return -EFAULT; | ||
1611 | |||
1612 | fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1613 | |||
1614 | #ifdef DEBUG | ||
1615 | { | ||
1616 | lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str); | ||
1617 | lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id)); | ||
1618 | } | ||
1619 | #endif | ||
1620 | |||
1621 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1622 | cmd_act_fwt_access_list, | ||
1623 | cmd_option_waitforrsp, 0, (void *)&fwt_access); | ||
1624 | |||
1625 | if (ret == 0) | ||
1626 | print_route(fwt_access, pbuf); | ||
1627 | else | ||
1628 | pbuf += sprintf(pbuf, " (null)"); | ||
1629 | |||
1630 | wrq->u.data.length = strlen(out_str); | ||
1631 | if (copy_to_user(wrq->u.data.pointer, (char *)out_str, | ||
1632 | wrq->u.data.length)) { | ||
1633 | lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n"); | ||
1634 | return -EFAULT; | ||
1635 | } | ||
1636 | |||
1637 | LEAVE(); | ||
1638 | return 0; | ||
1639 | } | ||
1640 | |||
1641 | /** | ||
1642 | * @brief List an entry from the FRT table | ||
1643 | * @param priv A pointer to wlan_private structure | ||
1644 | * @param req A pointer to ifreq structure | ||
1645 | * @return 0 --success, otherwise fail | ||
1646 | */ | ||
1647 | static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req) | ||
1648 | { | ||
1649 | struct iwreq *wrq = (struct iwreq *)req; | ||
1650 | char in_str[64]; | ||
1651 | static struct cmd_ds_fwt_access fwt_access; | ||
1652 | char *ptr = in_str; | ||
1653 | static char out_str[128]; | ||
1654 | char *pbuf = out_str; | ||
1655 | int ret; | ||
1656 | |||
1657 | ENTER(); | ||
1658 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1659 | return -EFAULT; | ||
1660 | |||
1661 | fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1662 | |||
1663 | #ifdef DEBUG | ||
1664 | { | ||
1665 | lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str); | ||
1666 | lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id)); | ||
1667 | } | ||
1668 | #endif | ||
1669 | |||
1670 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1671 | cmd_act_fwt_access_list_route, | ||
1672 | cmd_option_waitforrsp, 0, (void *)&fwt_access); | ||
1673 | |||
1674 | if (ret == 0) { | ||
1675 | pbuf += sprintf(pbuf, " "); | ||
1676 | pbuf += eth_addr2str(fwt_access.da, pbuf); | ||
1677 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric)); | ||
1678 | pbuf += sprintf(pbuf, " %u", fwt_access.dir); | ||
1679 | /* note that the firmware returns the nid in the id field */ | ||
1680 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id)); | ||
1681 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn)); | ||
1682 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn)); | ||
1683 | pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount); | ||
1684 | pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl); | ||
1685 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration)); | ||
1686 | } else | ||
1687 | pbuf += sprintf(pbuf, " (null)"); | ||
1688 | |||
1689 | wrq->u.data.length = strlen(out_str); | ||
1690 | if (copy_to_user(wrq->u.data.pointer, (char *)out_str, | ||
1691 | wrq->u.data.length)) { | ||
1692 | lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n"); | ||
1693 | return -EFAULT; | ||
1694 | } | ||
1695 | |||
1696 | LEAVE(); | ||
1697 | return 0; | ||
1698 | } | ||
1699 | |||
1700 | /** | ||
1701 | * @brief List an entry from the FNT table | ||
1702 | * @param priv A pointer to wlan_private structure | ||
1703 | * @param req A pointer to ifreq structure | ||
1704 | * @return 0 --success, otherwise fail | ||
1705 | */ | ||
1706 | static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req) | ||
1707 | { | ||
1708 | struct iwreq *wrq = (struct iwreq *)req; | ||
1709 | char in_str[8]; | ||
1710 | static struct cmd_ds_fwt_access fwt_access; | ||
1711 | char *ptr = in_str; | ||
1712 | static char out_str[128]; | ||
1713 | char *pbuf = out_str; | ||
1714 | int ret; | ||
1715 | |||
1716 | ENTER(); | ||
1717 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1718 | return -EFAULT; | ||
1719 | |||
1720 | memset(&fwt_access, 0, sizeof(fwt_access)); | ||
1721 | fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1722 | |||
1723 | #ifdef DEBUG | ||
1724 | { | ||
1725 | lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str); | ||
1726 | lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id)); | ||
1727 | } | ||
1728 | #endif | ||
1729 | |||
1730 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1731 | cmd_act_fwt_access_list_neighbor, | ||
1732 | cmd_option_waitforrsp, 0, | ||
1733 | (void *)&fwt_access); | ||
1734 | |||
1735 | if (ret == 0) { | ||
1736 | pbuf += sprintf(pbuf, " ra "); | ||
1737 | pbuf += eth_addr2str(fwt_access.ra, pbuf); | ||
1738 | pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode); | ||
1739 | pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr)); | ||
1740 | pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references)); | ||
1741 | } else | ||
1742 | pbuf += sprintf(pbuf, " (null)"); | ||
1743 | |||
1744 | wrq->u.data.length = strlen(out_str); | ||
1745 | if (copy_to_user(wrq->u.data.pointer, (char *)out_str, | ||
1746 | wrq->u.data.length)) { | ||
1747 | lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n"); | ||
1748 | return -EFAULT; | ||
1749 | } | ||
1750 | |||
1751 | LEAVE(); | ||
1752 | return 0; | ||
1753 | } | ||
1754 | |||
1755 | /** | ||
1756 | * @brief Cleans up the route (FRT) and neighbor (FNT) tables | ||
1757 | * (Garbage Collection) | ||
1758 | * @param priv A pointer to wlan_private structure | ||
1759 | * @param req A pointer to ifreq structure | ||
1760 | * @return 0 --success, otherwise fail | ||
1761 | */ | ||
1762 | static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req) | ||
1763 | { | ||
1764 | static struct cmd_ds_fwt_access fwt_access; | ||
1765 | int ret; | ||
1766 | |||
1767 | ENTER(); | ||
1768 | |||
1769 | lbs_pr_debug(1, "FWT: cleaning up\n"); | ||
1770 | |||
1771 | memset(&fwt_access, 0, sizeof(fwt_access)); | ||
1772 | |||
1773 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1774 | cmd_act_fwt_access_cleanup, | ||
1775 | cmd_option_waitforrsp, 0, | ||
1776 | (void *)&fwt_access); | ||
1777 | |||
1778 | if (ret == 0) | ||
1779 | req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); | ||
1780 | else | ||
1781 | return -EFAULT; | ||
1782 | |||
1783 | LEAVE(); | ||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | /** | ||
1788 | * @brief Gets firmware internal time (debug purposes) | ||
1789 | * @param priv A pointer to wlan_private structure | ||
1790 | * @param req A pointer to ifreq structure | ||
1791 | * @return 0 --success, otherwise fail | ||
1792 | */ | ||
1793 | static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req) | ||
1794 | { | ||
1795 | static struct cmd_ds_fwt_access fwt_access; | ||
1796 | int ret; | ||
1797 | |||
1798 | ENTER(); | ||
1799 | |||
1800 | lbs_pr_debug(1, "FWT: getting time\n"); | ||
1801 | |||
1802 | memset(&fwt_access, 0, sizeof(fwt_access)); | ||
1803 | |||
1804 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1805 | cmd_act_fwt_access_time, | ||
1806 | cmd_option_waitforrsp, 0, | ||
1807 | (void *)&fwt_access); | ||
1808 | |||
1809 | if (ret == 0) | ||
1810 | req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); | ||
1811 | else | ||
1812 | return -EFAULT; | ||
1813 | |||
1814 | LEAVE(); | ||
1815 | return 0; | ||
1816 | } | ||
1817 | |||
1818 | /** | ||
1819 | * @brief Gets mesh ttl from firmware | ||
1820 | * @param priv A pointer to wlan_private structure | ||
1821 | * @param req A pointer to ifreq structure | ||
1822 | * @return 0 --success, otherwise fail | ||
1823 | */ | ||
1824 | static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req) | ||
1825 | { | ||
1826 | struct cmd_ds_mesh_access mesh_access; | ||
1827 | int ret; | ||
1828 | |||
1829 | ENTER(); | ||
1830 | |||
1831 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
1832 | |||
1833 | ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, | ||
1834 | cmd_act_mesh_get_ttl, | ||
1835 | cmd_option_waitforrsp, 0, | ||
1836 | (void *)&mesh_access); | ||
1837 | |||
1838 | if (ret == 0) { | ||
1839 | req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0])); | ||
1840 | } | ||
1841 | else | ||
1842 | return -EFAULT; | ||
1843 | |||
1844 | LEAVE(); | ||
1845 | return 0; | ||
1846 | } | ||
1847 | |||
1848 | /** | ||
1849 | * @brief Gets mesh ttl from firmware | ||
1850 | * @param priv A pointer to wlan_private structure | ||
1851 | * @param ttl New ttl value | ||
1852 | * @return 0 --success, otherwise fail | ||
1853 | */ | ||
1854 | static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl) | ||
1855 | { | ||
1856 | struct cmd_ds_mesh_access mesh_access; | ||
1857 | int ret; | ||
1858 | |||
1859 | ENTER(); | ||
1860 | |||
1861 | if( (ttl > 0xff) || (ttl < 0) ) | ||
1862 | return -EINVAL; | ||
1863 | |||
1864 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
1865 | mesh_access.data[0] = ttl; | ||
1866 | |||
1867 | ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, | ||
1868 | cmd_act_mesh_set_ttl, | ||
1869 | cmd_option_waitforrsp, 0, | ||
1870 | (void *)&mesh_access); | ||
1871 | |||
1872 | if (ret != 0) | ||
1873 | ret = -EFAULT; | ||
1874 | |||
1875 | LEAVE(); | ||
1876 | return ret; | ||
1877 | } | ||
1878 | |||
1879 | /** | ||
1880 | * @brief ioctl function - entry point | ||
1881 | * | ||
1882 | * @param dev A pointer to net_device structure | ||
1883 | * @param req A pointer to ifreq structure | ||
1884 | * @param cmd command | ||
1885 | * @return 0--success, otherwise fail | ||
1886 | */ | ||
1887 | int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) | ||
1888 | { | ||
1889 | int subcmd = 0; | ||
1890 | int idata = 0; | ||
1891 | int *pdata; | ||
1892 | int ret = 0; | ||
1893 | wlan_private *priv = dev->priv; | ||
1894 | wlan_adapter *adapter = priv->adapter; | ||
1895 | struct iwreq *wrq = (struct iwreq *)req; | ||
1896 | |||
1897 | ENTER(); | ||
1898 | |||
1899 | lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd); | ||
1900 | switch (cmd) { | ||
1901 | case WLANSCAN_TYPE: | ||
1902 | lbs_pr_debug(1, "Scan type Ioctl\n"); | ||
1903 | ret = wlan_scan_type_ioctl(priv, wrq); | ||
1904 | break; | ||
1905 | |||
1906 | case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */ | ||
1907 | switch (wrq->u.data.flags) { | ||
1908 | case WLANDEAUTH: | ||
1909 | lbs_pr_debug(1, "Deauth\n"); | ||
1910 | libertas_send_deauth(priv); | ||
1911 | break; | ||
1912 | |||
1913 | case WLANADHOCSTOP: | ||
1914 | lbs_pr_debug(1, "Adhoc stop\n"); | ||
1915 | ret = libertas_do_adhocstop_ioctl(priv); | ||
1916 | break; | ||
1917 | |||
1918 | case WLANRADIOON: | ||
1919 | wlan_radio_ioctl(priv, 1); | ||
1920 | break; | ||
1921 | |||
1922 | case WLANRADIOOFF: | ||
1923 | wlan_radio_ioctl(priv, 0); | ||
1924 | break; | ||
1925 | case WLANWLANIDLEON: | ||
1926 | libertas_idle_on(priv); | ||
1927 | break; | ||
1928 | case WLANWLANIDLEOFF: | ||
1929 | libertas_idle_off(priv); | ||
1930 | break; | ||
1931 | case WLAN_SUBCMD_BT_RESET: /* bt_reset */ | ||
1932 | wlan_bt_reset_ioctl(priv); | ||
1933 | break; | ||
1934 | case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */ | ||
1935 | wlan_fwt_reset_ioctl(priv); | ||
1936 | break; | ||
1937 | } /* End of switch */ | ||
1938 | break; | ||
1939 | |||
1940 | case WLANSETWPAIE: | ||
1941 | ret = wlan_setwpaie_ioctl(priv, req); | ||
1942 | break; | ||
1943 | case WLAN_SETINT_GETINT: | ||
1944 | /* The first 4 bytes of req->ifr_data is sub-ioctl number | ||
1945 | * after 4 bytes sits the payload. | ||
1946 | */ | ||
1947 | subcmd = (int)req->ifr_data; //from iwpriv subcmd | ||
1948 | switch (subcmd) { | ||
1949 | case WLANNF: | ||
1950 | ret = wlan_get_nf(priv, wrq); | ||
1951 | break; | ||
1952 | case WLANRSSI: | ||
1953 | ret = wlan_get_rssi(priv, wrq); | ||
1954 | break; | ||
1955 | case WLANENABLE11D: | ||
1956 | ret = libertas_cmd_enable_11d(priv, wrq); | ||
1957 | break; | ||
1958 | case WLANADHOCGRATE: | ||
1959 | ret = wlan_do_set_grate_ioctl(priv, wrq); | ||
1960 | break; | ||
1961 | case WLAN_SUBCMD_SET_PRESCAN: | ||
1962 | ret = wlan_subcmd_setprescan_ioctl(priv, wrq); | ||
1963 | break; | ||
1964 | } | ||
1965 | break; | ||
1966 | |||
1967 | case WLAN_SETONEINT_GETONEINT: | ||
1968 | switch (wrq->u.data.flags) { | ||
1969 | case WLAN_BEACON_INTERVAL: | ||
1970 | ret = wlan_beacon_interval(priv, wrq); | ||
1971 | break; | ||
1972 | |||
1973 | case WLAN_LISTENINTRVL: | ||
1974 | if (!wrq->u.data.length) { | ||
1975 | int data; | ||
1976 | lbs_pr_debug(1, "Get locallisteninterval value\n"); | ||
1977 | #define GET_ONE_INT 1 | ||
1978 | data = adapter->locallisteninterval; | ||
1979 | if (copy_to_user(wrq->u.data.pointer, | ||
1980 | &data, sizeof(int))) { | ||
1981 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
1982 | return -EFAULT; | ||
1983 | } | ||
1984 | |||
1985 | wrq->u.data.length = GET_ONE_INT; | ||
1986 | } else { | ||
1987 | int data; | ||
1988 | if (copy_from_user | ||
1989 | (&data, wrq->u.data.pointer, sizeof(int))) { | ||
1990 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
1991 | return -EFAULT; | ||
1992 | } | ||
1993 | |||
1994 | lbs_pr_debug(1, "Set locallisteninterval = %d\n", | ||
1995 | data); | ||
1996 | #define MAX_U16_VAL 65535 | ||
1997 | if (data > MAX_U16_VAL) { | ||
1998 | lbs_pr_debug(1, "Exceeds U16 value\n"); | ||
1999 | return -EINVAL; | ||
2000 | } | ||
2001 | adapter->locallisteninterval = data; | ||
2002 | } | ||
2003 | break; | ||
2004 | case WLAN_TXCONTROL: | ||
2005 | ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl | ||
2006 | break; | ||
2007 | |||
2008 | case WLAN_NULLPKTINTERVAL: | ||
2009 | ret = wlan_null_pkt_interval(priv, wrq); | ||
2010 | break; | ||
2011 | |||
2012 | default: | ||
2013 | ret = -EOPNOTSUPP; | ||
2014 | break; | ||
2015 | } | ||
2016 | break; | ||
2017 | |||
2018 | case WLAN_SETONEINT_GETNONE: | ||
2019 | /* The first 4 bytes of req->ifr_data is sub-ioctl number | ||
2020 | * after 4 bytes sits the payload. | ||
2021 | */ | ||
2022 | subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd | ||
2023 | |||
2024 | if (!subcmd) | ||
2025 | subcmd = (int)req->ifr_data; //from iwpriv subcmd | ||
2026 | |||
2027 | switch (subcmd) { | ||
2028 | case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */ | ||
2029 | idata = SUBCMD_DATA(wrq); | ||
2030 | ret = setrxantenna(priv, idata); | ||
2031 | break; | ||
2032 | case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */ | ||
2033 | idata = SUBCMD_DATA(wrq); | ||
2034 | ret = settxantenna(priv, idata); | ||
2035 | break; | ||
2036 | case WLAN_SET_ATIM_WINDOW: | ||
2037 | adapter->atimwindow = SUBCMD_DATA(wrq); | ||
2038 | adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50); | ||
2039 | break; | ||
2040 | case WLANSETBCNAVG: | ||
2041 | adapter->bcn_avg_factor = SUBCMD_DATA(wrq); | ||
2042 | if (adapter->bcn_avg_factor == 0) | ||
2043 | adapter->bcn_avg_factor = | ||
2044 | DEFAULT_BCN_AVG_FACTOR; | ||
2045 | if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR) | ||
2046 | adapter->bcn_avg_factor = | ||
2047 | DEFAULT_BCN_AVG_FACTOR; | ||
2048 | break; | ||
2049 | case WLANSETDATAAVG: | ||
2050 | adapter->data_avg_factor = SUBCMD_DATA(wrq); | ||
2051 | if (adapter->data_avg_factor == 0) | ||
2052 | adapter->data_avg_factor = | ||
2053 | DEFAULT_DATA_AVG_FACTOR; | ||
2054 | if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR) | ||
2055 | adapter->data_avg_factor = | ||
2056 | DEFAULT_DATA_AVG_FACTOR; | ||
2057 | break; | ||
2058 | case WLANSETREGION: | ||
2059 | idata = SUBCMD_DATA(wrq); | ||
2060 | ret = wlan_set_region(priv, (u16) idata); | ||
2061 | break; | ||
2062 | |||
2063 | case WLAN_SET_LISTEN_INTERVAL: | ||
2064 | idata = SUBCMD_DATA(wrq); | ||
2065 | adapter->listeninterval = (u16) idata; | ||
2066 | break; | ||
2067 | |||
2068 | case WLAN_SET_MULTIPLE_DTIM: | ||
2069 | ret = wlan_set_multiple_dtim_ioctl(priv, req); | ||
2070 | break; | ||
2071 | |||
2072 | case WLANSETAUTHALG: | ||
2073 | ret = wlan_setauthalg_ioctl(priv, req); | ||
2074 | break; | ||
2075 | |||
2076 | case WLANSET8021XAUTHALG: | ||
2077 | ret = wlan_set8021xauthalg_ioctl(priv, req); | ||
2078 | break; | ||
2079 | |||
2080 | case WLANSETENCRYPTIONMODE: | ||
2081 | ret = wlan_setencryptionmode_ioctl(priv, req); | ||
2082 | break; | ||
2083 | |||
2084 | case WLAN_SET_LINKMODE: | ||
2085 | ret = wlan_set_linkmode_ioctl(priv, req); | ||
2086 | break; | ||
2087 | |||
2088 | case WLAN_SET_RADIOMODE: | ||
2089 | ret = wlan_set_radiomode_ioctl(priv, req); | ||
2090 | break; | ||
2091 | |||
2092 | case WLAN_SET_DEBUGMODE: | ||
2093 | ret = wlan_set_debugmode_ioctl(priv, req); | ||
2094 | break; | ||
2095 | |||
2096 | case WLAN_SUBCMD_MESH_SET_TTL: | ||
2097 | idata = SUBCMD_DATA(wrq); | ||
2098 | ret = wlan_mesh_set_ttl_ioctl(priv, idata); | ||
2099 | break; | ||
2100 | |||
2101 | default: | ||
2102 | ret = -EOPNOTSUPP; | ||
2103 | break; | ||
2104 | } | ||
2105 | |||
2106 | break; | ||
2107 | |||
2108 | case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */ | ||
2109 | /* | ||
2110 | * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is | ||
2111 | * in flags of iwreq structure, otherwise it will be in | ||
2112 | * mode member of iwreq structure. | ||
2113 | */ | ||
2114 | switch ((int)wrq->u.data.flags) { | ||
2115 | case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */ | ||
2116 | ret = wlan_subcmd_getrxantenna_ioctl(priv, req); | ||
2117 | break; | ||
2118 | |||
2119 | case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */ | ||
2120 | ret = wlan_subcmd_gettxantenna_ioctl(priv, req); | ||
2121 | break; | ||
2122 | |||
2123 | case WLAN_GET_TSF: | ||
2124 | ret = wlan_get_tsf_ioctl(priv, wrq); | ||
2125 | break; | ||
2126 | } | ||
2127 | break; | ||
2128 | |||
2129 | case WLAN_SET128CHAR_GET128CHAR: | ||
2130 | switch ((int)wrq->u.data.flags) { | ||
2131 | |||
2132 | case WLANSCAN_MODE: | ||
2133 | lbs_pr_debug(1, "Scan mode Ioctl\n"); | ||
2134 | ret = wlan_scan_mode_ioctl(priv, wrq); | ||
2135 | break; | ||
2136 | |||
2137 | case WLAN_GET_ADHOC_STATUS: | ||
2138 | ret = wlan_get_adhoc_status_ioctl(priv, wrq); | ||
2139 | break; | ||
2140 | case WLAN_SUBCMD_BT_ADD: | ||
2141 | ret = wlan_bt_add_ioctl(priv, req); | ||
2142 | break; | ||
2143 | case WLAN_SUBCMD_BT_DEL: | ||
2144 | ret = wlan_bt_del_ioctl(priv, req); | ||
2145 | break; | ||
2146 | case WLAN_SUBCMD_BT_LIST: | ||
2147 | ret = wlan_bt_list_ioctl(priv, req); | ||
2148 | break; | ||
2149 | case WLAN_SUBCMD_FWT_ADD: | ||
2150 | ret = wlan_fwt_add_ioctl(priv, req); | ||
2151 | break; | ||
2152 | case WLAN_SUBCMD_FWT_DEL: | ||
2153 | ret = wlan_fwt_del_ioctl(priv, req); | ||
2154 | break; | ||
2155 | case WLAN_SUBCMD_FWT_LOOKUP: | ||
2156 | ret = wlan_fwt_lookup_ioctl(priv, req); | ||
2157 | break; | ||
2158 | case WLAN_SUBCMD_FWT_LIST_NEIGHBOR: | ||
2159 | ret = wlan_fwt_list_neighbor_ioctl(priv, req); | ||
2160 | break; | ||
2161 | case WLAN_SUBCMD_FWT_LIST: | ||
2162 | ret = wlan_fwt_list_ioctl(priv, req); | ||
2163 | break; | ||
2164 | case WLAN_SUBCMD_FWT_LIST_ROUTE: | ||
2165 | ret = wlan_fwt_list_route_ioctl(priv, req); | ||
2166 | break; | ||
2167 | } | ||
2168 | break; | ||
2169 | |||
2170 | case WLAN_SETNONE_GETONEINT: | ||
2171 | switch ((int)req->ifr_data) { | ||
2172 | case WLANGETBCNAVG: | ||
2173 | pdata = (int *)wrq->u.name; | ||
2174 | *pdata = (int)adapter->bcn_avg_factor; | ||
2175 | break; | ||
2176 | |||
2177 | case WLANGETREGION: | ||
2178 | pdata = (int *)wrq->u.name; | ||
2179 | *pdata = (int)adapter->regioncode; | ||
2180 | break; | ||
2181 | |||
2182 | case WLAN_GET_LISTEN_INTERVAL: | ||
2183 | pdata = (int *)wrq->u.name; | ||
2184 | *pdata = (int)adapter->listeninterval; | ||
2185 | break; | ||
2186 | |||
2187 | case WLAN_GET_LINKMODE: | ||
2188 | req->ifr_data = (char *)((u32) adapter->linkmode); | ||
2189 | break; | ||
2190 | |||
2191 | case WLAN_GET_RADIOMODE: | ||
2192 | req->ifr_data = (char *)((u32) adapter->radiomode); | ||
2193 | break; | ||
2194 | |||
2195 | case WLAN_GET_DEBUGMODE: | ||
2196 | req->ifr_data = (char *)((u32) adapter->debugmode); | ||
2197 | break; | ||
2198 | |||
2199 | case WLAN_GET_MULTIPLE_DTIM: | ||
2200 | pdata = (int *)wrq->u.name; | ||
2201 | *pdata = (int)adapter->multipledtim; | ||
2202 | break; | ||
2203 | case WLAN_GET_TX_RATE: | ||
2204 | ret = wlan_get_txrate_ioctl(priv, req); | ||
2205 | break; | ||
2206 | case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */ | ||
2207 | ret = wlan_fwt_cleanup_ioctl(priv, req); | ||
2208 | break; | ||
2209 | |||
2210 | case WLAN_SUBCMD_FWT_TIME: /* fwt_time */ | ||
2211 | ret = wlan_fwt_time_ioctl(priv, req); | ||
2212 | break; | ||
2213 | |||
2214 | case WLAN_SUBCMD_MESH_GET_TTL: | ||
2215 | ret = wlan_mesh_get_ttl_ioctl(priv, req); | ||
2216 | break; | ||
2217 | |||
2218 | default: | ||
2219 | ret = -EOPNOTSUPP; | ||
2220 | |||
2221 | } | ||
2222 | |||
2223 | break; | ||
2224 | |||
2225 | case WLANGETLOG: | ||
2226 | ret = wlan_do_getlog_ioctl(priv, wrq); | ||
2227 | break; | ||
2228 | |||
2229 | case WLAN_SET_GET_SIXTEEN_INT: | ||
2230 | switch ((int)wrq->u.data.flags) { | ||
2231 | case WLAN_TPCCFG: | ||
2232 | { | ||
2233 | int data[5]; | ||
2234 | struct cmd_ds_802_11_tpc_cfg cfg; | ||
2235 | memset(&cfg, 0, sizeof(cfg)); | ||
2236 | if ((wrq->u.data.length > 1) | ||
2237 | && (wrq->u.data.length != 5)) | ||
2238 | return -1; | ||
2239 | |||
2240 | if (wrq->u.data.length == 0) { | ||
2241 | cfg.action = | ||
2242 | cpu_to_le16 | ||
2243 | (cmd_act_get); | ||
2244 | } else { | ||
2245 | if (copy_from_user | ||
2246 | (data, wrq->u.data.pointer, | ||
2247 | sizeof(int) * 5)) { | ||
2248 | lbs_pr_debug(1, | ||
2249 | "Copy from user failed\n"); | ||
2250 | return -EFAULT; | ||
2251 | } | ||
2252 | |||
2253 | cfg.action = | ||
2254 | cpu_to_le16 | ||
2255 | (cmd_act_set); | ||
2256 | cfg.enable = data[0]; | ||
2257 | cfg.usesnr = data[1]; | ||
2258 | cfg.P0 = data[2]; | ||
2259 | cfg.P1 = data[3]; | ||
2260 | cfg.P2 = data[4]; | ||
2261 | } | ||
2262 | |||
2263 | ret = | ||
2264 | libertas_prepare_and_send_command(priv, | ||
2265 | cmd_802_11_tpc_cfg, | ||
2266 | 0, | ||
2267 | cmd_option_waitforrsp, | ||
2268 | 0, (void *)&cfg); | ||
2269 | |||
2270 | data[0] = cfg.enable; | ||
2271 | data[1] = cfg.usesnr; | ||
2272 | data[2] = cfg.P0; | ||
2273 | data[3] = cfg.P1; | ||
2274 | data[4] = cfg.P2; | ||
2275 | if (copy_to_user | ||
2276 | (wrq->u.data.pointer, data, | ||
2277 | sizeof(int) * 5)) { | ||
2278 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
2279 | return -EFAULT; | ||
2280 | } | ||
2281 | |||
2282 | wrq->u.data.length = 5; | ||
2283 | } | ||
2284 | break; | ||
2285 | |||
2286 | case WLAN_POWERCFG: | ||
2287 | { | ||
2288 | int data[4]; | ||
2289 | struct cmd_ds_802_11_pwr_cfg cfg; | ||
2290 | memset(&cfg, 0, sizeof(cfg)); | ||
2291 | if ((wrq->u.data.length > 1) | ||
2292 | && (wrq->u.data.length != 4)) | ||
2293 | return -1; | ||
2294 | if (wrq->u.data.length == 0) { | ||
2295 | cfg.action = | ||
2296 | cpu_to_le16 | ||
2297 | (cmd_act_get); | ||
2298 | } else { | ||
2299 | if (copy_from_user | ||
2300 | (data, wrq->u.data.pointer, | ||
2301 | sizeof(int) * 4)) { | ||
2302 | lbs_pr_debug(1, | ||
2303 | "Copy from user failed\n"); | ||
2304 | return -EFAULT; | ||
2305 | } | ||
2306 | |||
2307 | cfg.action = | ||
2308 | cpu_to_le16 | ||
2309 | (cmd_act_set); | ||
2310 | cfg.enable = data[0]; | ||
2311 | cfg.PA_P0 = data[1]; | ||
2312 | cfg.PA_P1 = data[2]; | ||
2313 | cfg.PA_P2 = data[3]; | ||
2314 | } | ||
2315 | ret = | ||
2316 | libertas_prepare_and_send_command(priv, | ||
2317 | cmd_802_11_pwr_cfg, | ||
2318 | 0, | ||
2319 | cmd_option_waitforrsp, | ||
2320 | 0, (void *)&cfg); | ||
2321 | data[0] = cfg.enable; | ||
2322 | data[1] = cfg.PA_P0; | ||
2323 | data[2] = cfg.PA_P1; | ||
2324 | data[3] = cfg.PA_P2; | ||
2325 | if (copy_to_user | ||
2326 | (wrq->u.data.pointer, data, | ||
2327 | sizeof(int) * 4)) { | ||
2328 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
2329 | return -EFAULT; | ||
2330 | } | ||
2331 | |||
2332 | wrq->u.data.length = 4; | ||
2333 | } | ||
2334 | break; | ||
2335 | case WLAN_AUTO_FREQ_SET: | ||
2336 | { | ||
2337 | int data[3]; | ||
2338 | struct cmd_ds_802_11_afc afc; | ||
2339 | memset(&afc, 0, sizeof(afc)); | ||
2340 | if (wrq->u.data.length != 3) | ||
2341 | return -1; | ||
2342 | if (copy_from_user | ||
2343 | (data, wrq->u.data.pointer, | ||
2344 | sizeof(int) * 3)) { | ||
2345 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
2346 | return -EFAULT; | ||
2347 | } | ||
2348 | afc.afc_auto = data[0]; | ||
2349 | |||
2350 | if (afc.afc_auto != 0) { | ||
2351 | afc.threshold = data[1]; | ||
2352 | afc.period = data[2]; | ||
2353 | } else { | ||
2354 | afc.timing_offset = data[1]; | ||
2355 | afc.carrier_offset = data[2]; | ||
2356 | } | ||
2357 | ret = | ||
2358 | libertas_prepare_and_send_command(priv, | ||
2359 | cmd_802_11_set_afc, | ||
2360 | 0, | ||
2361 | cmd_option_waitforrsp, | ||
2362 | 0, (void *)&afc); | ||
2363 | } | ||
2364 | break; | ||
2365 | case WLAN_AUTO_FREQ_GET: | ||
2366 | { | ||
2367 | int data[3]; | ||
2368 | struct cmd_ds_802_11_afc afc; | ||
2369 | memset(&afc, 0, sizeof(afc)); | ||
2370 | ret = | ||
2371 | libertas_prepare_and_send_command(priv, | ||
2372 | cmd_802_11_get_afc, | ||
2373 | 0, | ||
2374 | cmd_option_waitforrsp, | ||
2375 | 0, (void *)&afc); | ||
2376 | data[0] = afc.afc_auto; | ||
2377 | data[1] = afc.timing_offset; | ||
2378 | data[2] = afc.carrier_offset; | ||
2379 | if (copy_to_user | ||
2380 | (wrq->u.data.pointer, data, | ||
2381 | sizeof(int) * 3)) { | ||
2382 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
2383 | return -EFAULT; | ||
2384 | } | ||
2385 | |||
2386 | wrq->u.data.length = 3; | ||
2387 | } | ||
2388 | break; | ||
2389 | case WLAN_SCANPROBES: | ||
2390 | { | ||
2391 | int data; | ||
2392 | if (wrq->u.data.length > 0) { | ||
2393 | if (copy_from_user | ||
2394 | (&data, wrq->u.data.pointer, | ||
2395 | sizeof(int))) { | ||
2396 | lbs_pr_debug(1, | ||
2397 | "Copy from user failed\n"); | ||
2398 | return -EFAULT; | ||
2399 | } | ||
2400 | |||
2401 | adapter->scanprobes = data; | ||
2402 | } else { | ||
2403 | data = adapter->scanprobes; | ||
2404 | if (copy_to_user | ||
2405 | (wrq->u.data.pointer, &data, | ||
2406 | sizeof(int))) { | ||
2407 | lbs_pr_debug(1, | ||
2408 | "Copy to user failed\n"); | ||
2409 | return -EFAULT; | ||
2410 | } | ||
2411 | } | ||
2412 | wrq->u.data.length = 1; | ||
2413 | } | ||
2414 | break; | ||
2415 | case WLAN_LED_GPIO_CTRL: | ||
2416 | { | ||
2417 | int i; | ||
2418 | int data[16]; | ||
2419 | |||
2420 | struct cmd_ds_802_11_led_ctrl ctrl; | ||
2421 | struct mrvlietypes_ledgpio *gpio = | ||
2422 | (struct mrvlietypes_ledgpio *) ctrl.data; | ||
2423 | |||
2424 | memset(&ctrl, 0, sizeof(ctrl)); | ||
2425 | if (wrq->u.data.length > MAX_LEDS * 2) | ||
2426 | return -ENOTSUPP; | ||
2427 | if ((wrq->u.data.length % 2) != 0) | ||
2428 | return -ENOTSUPP; | ||
2429 | if (wrq->u.data.length == 0) { | ||
2430 | ctrl.action = | ||
2431 | cpu_to_le16 | ||
2432 | (cmd_act_get); | ||
2433 | } else { | ||
2434 | if (copy_from_user | ||
2435 | (data, wrq->u.data.pointer, | ||
2436 | sizeof(int) * | ||
2437 | wrq->u.data.length)) { | ||
2438 | lbs_pr_debug(1, | ||
2439 | "Copy from user failed\n"); | ||
2440 | return -EFAULT; | ||
2441 | } | ||
2442 | |||
2443 | ctrl.action = | ||
2444 | cpu_to_le16 | ||
2445 | (cmd_act_set); | ||
2446 | ctrl.numled = cpu_to_le16(0); | ||
2447 | gpio->header.type = | ||
2448 | cpu_to_le16(TLV_TYPE_LED_GPIO); | ||
2449 | gpio->header.len = wrq->u.data.length; | ||
2450 | for (i = 0; i < wrq->u.data.length; | ||
2451 | i += 2) { | ||
2452 | gpio->ledpin[i / 2].led = | ||
2453 | data[i]; | ||
2454 | gpio->ledpin[i / 2].pin = | ||
2455 | data[i + 1]; | ||
2456 | } | ||
2457 | } | ||
2458 | ret = | ||
2459 | libertas_prepare_and_send_command(priv, | ||
2460 | cmd_802_11_led_gpio_ctrl, | ||
2461 | 0, | ||
2462 | cmd_option_waitforrsp, | ||
2463 | 0, (void *)&ctrl); | ||
2464 | for (i = 0; i < gpio->header.len; i += 2) { | ||
2465 | data[i] = gpio->ledpin[i / 2].led; | ||
2466 | data[i + 1] = gpio->ledpin[i / 2].pin; | ||
2467 | } | ||
2468 | if (copy_to_user(wrq->u.data.pointer, data, | ||
2469 | sizeof(int) * | ||
2470 | gpio->header.len)) { | ||
2471 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
2472 | return -EFAULT; | ||
2473 | } | ||
2474 | |||
2475 | wrq->u.data.length = gpio->header.len; | ||
2476 | } | ||
2477 | break; | ||
2478 | case WLAN_ADAPT_RATESET: | ||
2479 | ret = wlan_adapt_rateset(priv, wrq); | ||
2480 | break; | ||
2481 | case WLAN_INACTIVITY_TIMEOUT: | ||
2482 | ret = wlan_inactivity_timeout(priv, wrq); | ||
2483 | break; | ||
2484 | case WLANSNR: | ||
2485 | ret = wlan_get_snr(priv, wrq); | ||
2486 | break; | ||
2487 | case WLAN_GET_RXINFO: | ||
2488 | ret = wlan_get_rxinfo(priv, wrq); | ||
2489 | } | ||
2490 | break; | ||
2491 | |||
2492 | default: | ||
2493 | ret = -EINVAL; | ||
2494 | break; | ||
2495 | } | ||
2496 | LEAVE(); | ||
2497 | return ret; | ||
2498 | } | ||
2499 | |||
2500 | |||
diff --git a/drivers/net/wireless/libertas/join.c b/drivers/net/wireless/libertas/join.c new file mode 100644 index 000000000000..11682cbe752b --- /dev/null +++ b/drivers/net/wireless/libertas/join.c | |||
@@ -0,0 +1,1055 @@ | |||
1 | /** | ||
2 | * Functions implementing wlan infrastructure and adhoc join routines, | ||
3 | * IOCTL handlers as well as command preperation and response routines | ||
4 | * for sending adhoc start, adhoc join, and association commands | ||
5 | * to the firmware. | ||
6 | */ | ||
7 | #include <linux/netdevice.h> | ||
8 | #include <linux/if_arp.h> | ||
9 | #include <linux/wireless.h> | ||
10 | |||
11 | #include <net/iw_handler.h> | ||
12 | |||
13 | #include "host.h" | ||
14 | #include "decl.h" | ||
15 | #include "join.h" | ||
16 | #include "dev.h" | ||
17 | |||
18 | /** | ||
19 | * @brief This function finds out the common rates between rate1 and rate2. | ||
20 | * | ||
21 | * It will fill common rates in rate1 as output if found. | ||
22 | * | ||
23 | * NOTE: Setting the MSB of the basic rates need to be taken | ||
24 | * care, either before or after calling this function | ||
25 | * | ||
26 | * @param adapter A pointer to wlan_adapter structure | ||
27 | * @param rate1 the buffer which keeps input and output | ||
28 | * @param rate1_size the size of rate1 buffer | ||
29 | * @param rate2 the buffer which keeps rate2 | ||
30 | * @param rate2_size the size of rate2 buffer. | ||
31 | * | ||
32 | * @return 0 or -1 | ||
33 | */ | ||
34 | static int get_common_rates(wlan_adapter * adapter, u8 * rate1, | ||
35 | int rate1_size, u8 * rate2, int rate2_size) | ||
36 | { | ||
37 | u8 *ptr = rate1; | ||
38 | int ret = 0; | ||
39 | u8 tmp[30]; | ||
40 | int i; | ||
41 | |||
42 | memset(&tmp, 0, sizeof(tmp)); | ||
43 | memcpy(&tmp, rate1, min_t(size_t, rate1_size, sizeof(tmp))); | ||
44 | memset(rate1, 0, rate1_size); | ||
45 | |||
46 | /* Mask the top bit of the original values */ | ||
47 | for (i = 0; tmp[i] && i < sizeof(tmp); i++) | ||
48 | tmp[i] &= 0x7F; | ||
49 | |||
50 | for (i = 0; rate2[i] && i < rate2_size; i++) { | ||
51 | /* Check for Card Rate in tmp, excluding the top bit */ | ||
52 | if (strchr(tmp, rate2[i] & 0x7F)) { | ||
53 | /* values match, so copy the Card Rate to rate1 */ | ||
54 | *rate1++ = rate2[i]; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | lbs_dbg_hex("rate1 (AP) rates:", tmp, sizeof(tmp)); | ||
59 | lbs_dbg_hex("rate2 (Card) rates:", rate2, rate2_size); | ||
60 | lbs_dbg_hex("Common rates:", ptr, rate1_size); | ||
61 | lbs_pr_debug(1, "Tx datarate is set to 0x%X\n", adapter->datarate); | ||
62 | |||
63 | if (!adapter->is_datarate_auto) { | ||
64 | while (*ptr) { | ||
65 | if ((*ptr & 0x7f) == adapter->datarate) { | ||
66 | ret = 0; | ||
67 | goto done; | ||
68 | } | ||
69 | ptr++; | ||
70 | } | ||
71 | lbs_pr_alert( "Previously set fixed data rate %#x isn't " | ||
72 | "compatible with the network.\n", adapter->datarate); | ||
73 | |||
74 | ret = -1; | ||
75 | goto done; | ||
76 | } | ||
77 | |||
78 | ret = 0; | ||
79 | done: | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | int libertas_send_deauth(wlan_private * priv) | ||
84 | { | ||
85 | wlan_adapter *adapter = priv->adapter; | ||
86 | int ret = 0; | ||
87 | |||
88 | if (adapter->inframode == wlan802_11infrastructure && | ||
89 | adapter->connect_status == libertas_connected) | ||
90 | ret = libertas_send_deauthentication(priv); | ||
91 | else | ||
92 | ret = -ENOTSUPP; | ||
93 | |||
94 | return ret; | ||
95 | } | ||
96 | |||
97 | int libertas_do_adhocstop_ioctl(wlan_private * priv) | ||
98 | { | ||
99 | wlan_adapter *adapter = priv->adapter; | ||
100 | int ret = 0; | ||
101 | |||
102 | if (adapter->inframode == wlan802_11ibss && | ||
103 | adapter->connect_status == libertas_connected) | ||
104 | ret = libertas_stop_adhoc_network(priv); | ||
105 | else | ||
106 | ret = -ENOTSUPP; | ||
107 | |||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * @brief Associate to a specific BSS discovered in a scan | ||
113 | * | ||
114 | * @param priv A pointer to wlan_private structure | ||
115 | * @param pbssdesc Pointer to the BSS descriptor to associate with. | ||
116 | * | ||
117 | * @return 0-success, otherwise fail | ||
118 | */ | ||
119 | int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc) | ||
120 | { | ||
121 | wlan_adapter *adapter = priv->adapter; | ||
122 | int ret; | ||
123 | |||
124 | ENTER(); | ||
125 | |||
126 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_authenticate, | ||
127 | 0, cmd_option_waitforrsp, | ||
128 | 0, pbssdesc->macaddress); | ||
129 | |||
130 | if (ret) { | ||
131 | LEAVE(); | ||
132 | return ret; | ||
133 | } | ||
134 | |||
135 | /* set preamble to firmware */ | ||
136 | if (adapter->capinfo.shortpreamble && pbssdesc->cap.shortpreamble) | ||
137 | adapter->preamble = cmd_type_short_preamble; | ||
138 | else | ||
139 | adapter->preamble = cmd_type_long_preamble; | ||
140 | |||
141 | libertas_set_radio_control(priv); | ||
142 | |||
143 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_associate, | ||
144 | 0, cmd_option_waitforrsp, 0, pbssdesc); | ||
145 | |||
146 | LEAVE(); | ||
147 | return ret; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * @brief Start an Adhoc Network | ||
152 | * | ||
153 | * @param priv A pointer to wlan_private structure | ||
154 | * @param adhocssid The ssid of the Adhoc Network | ||
155 | * @return 0--success, -1--fail | ||
156 | */ | ||
157 | int libertas_start_adhoc_network(wlan_private * priv, struct WLAN_802_11_SSID *adhocssid) | ||
158 | { | ||
159 | wlan_adapter *adapter = priv->adapter; | ||
160 | int ret = 0; | ||
161 | |||
162 | adapter->adhoccreate = 1; | ||
163 | |||
164 | if (!adapter->capinfo.shortpreamble) { | ||
165 | lbs_pr_debug(1, "AdhocStart: Long preamble\n"); | ||
166 | adapter->preamble = cmd_type_long_preamble; | ||
167 | } else { | ||
168 | lbs_pr_debug(1, "AdhocStart: Short preamble\n"); | ||
169 | adapter->preamble = cmd_type_short_preamble; | ||
170 | } | ||
171 | |||
172 | libertas_set_radio_control(priv); | ||
173 | |||
174 | lbs_pr_debug(1, "Adhoc channel = %d\n", adapter->adhocchannel); | ||
175 | lbs_pr_debug(1, "curbssparams.channel = %d\n", | ||
176 | adapter->curbssparams.channel); | ||
177 | lbs_pr_debug(1, "curbssparams.band = %d\n", adapter->curbssparams.band); | ||
178 | |||
179 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_start, | ||
180 | 0, cmd_option_waitforrsp, 0, adhocssid); | ||
181 | |||
182 | return ret; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * @brief Join an adhoc network found in a previous scan | ||
187 | * | ||
188 | * @param priv A pointer to wlan_private structure | ||
189 | * @param pbssdesc Pointer to a BSS descriptor found in a previous scan | ||
190 | * to attempt to join | ||
191 | * | ||
192 | * @return 0--success, -1--fail | ||
193 | */ | ||
194 | int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor * pbssdesc) | ||
195 | { | ||
196 | wlan_adapter *adapter = priv->adapter; | ||
197 | int ret = 0; | ||
198 | |||
199 | lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid =%s\n", | ||
200 | adapter->curbssparams.ssid.ssid); | ||
201 | lbs_pr_debug(1, "libertas_join_adhoc_network: CurBss.ssid_len =%u\n", | ||
202 | adapter->curbssparams.ssid.ssidlength); | ||
203 | lbs_pr_debug(1, "libertas_join_adhoc_network: ssid =%s\n", pbssdesc->ssid.ssid); | ||
204 | lbs_pr_debug(1, "libertas_join_adhoc_network: ssid len =%u\n", | ||
205 | pbssdesc->ssid.ssidlength); | ||
206 | |||
207 | /* check if the requested SSID is already joined */ | ||
208 | if (adapter->curbssparams.ssid.ssidlength | ||
209 | && !libertas_SSID_cmp(&pbssdesc->ssid, &adapter->curbssparams.ssid) | ||
210 | && (adapter->curbssparams.bssdescriptor.inframode == | ||
211 | wlan802_11ibss)) { | ||
212 | |||
213 | lbs_pr_debug(1, | ||
214 | "ADHOC_J_CMD: New ad-hoc SSID is the same as current, " | ||
215 | "not attempting to re-join"); | ||
216 | |||
217 | return -1; | ||
218 | } | ||
219 | |||
220 | /*Use shortpreamble only when both creator and card supports | ||
221 | short preamble */ | ||
222 | if (!pbssdesc->cap.shortpreamble || !adapter->capinfo.shortpreamble) { | ||
223 | lbs_pr_debug(1, "AdhocJoin: Long preamble\n"); | ||
224 | adapter->preamble = cmd_type_long_preamble; | ||
225 | } else { | ||
226 | lbs_pr_debug(1, "AdhocJoin: Short preamble\n"); | ||
227 | adapter->preamble = cmd_type_short_preamble; | ||
228 | } | ||
229 | |||
230 | libertas_set_radio_control(priv); | ||
231 | |||
232 | lbs_pr_debug(1, "curbssparams.channel = %d\n", | ||
233 | adapter->curbssparams.channel); | ||
234 | lbs_pr_debug(1, "curbssparams.band = %c\n", adapter->curbssparams.band); | ||
235 | |||
236 | adapter->adhoccreate = 0; | ||
237 | |||
238 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_join, | ||
239 | 0, cmd_option_waitforrsp, | ||
240 | OID_802_11_SSID, pbssdesc); | ||
241 | |||
242 | return ret; | ||
243 | } | ||
244 | |||
245 | int libertas_stop_adhoc_network(wlan_private * priv) | ||
246 | { | ||
247 | return libertas_prepare_and_send_command(priv, cmd_802_11_ad_hoc_stop, | ||
248 | 0, cmd_option_waitforrsp, 0, NULL); | ||
249 | } | ||
250 | |||
251 | /** | ||
252 | * @brief Send Deauthentication Request | ||
253 | * | ||
254 | * @param priv A pointer to wlan_private structure | ||
255 | * @return 0--success, -1--fail | ||
256 | */ | ||
257 | int libertas_send_deauthentication(wlan_private * priv) | ||
258 | { | ||
259 | return libertas_prepare_and_send_command(priv, cmd_802_11_deauthenticate, | ||
260 | 0, cmd_option_waitforrsp, 0, NULL); | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * @brief Set Idle Off | ||
265 | * | ||
266 | * @param priv A pointer to wlan_private structure | ||
267 | * @return 0 --success, otherwise fail | ||
268 | */ | ||
269 | int libertas_idle_off(wlan_private * priv) | ||
270 | { | ||
271 | wlan_adapter *adapter = priv->adapter; | ||
272 | int ret = 0; | ||
273 | const u8 zeromac[] = { 0, 0, 0, 0, 0, 0 }; | ||
274 | int i; | ||
275 | |||
276 | ENTER(); | ||
277 | |||
278 | if (adapter->connect_status == libertas_disconnected) { | ||
279 | if (adapter->inframode == wlan802_11infrastructure) { | ||
280 | if (memcmp(adapter->previousbssid, zeromac, | ||
281 | sizeof(zeromac)) != 0) { | ||
282 | |||
283 | lbs_pr_debug(1, "Previous SSID = %s\n", | ||
284 | adapter->previousssid.ssid); | ||
285 | lbs_pr_debug(1, "Previous BSSID = " | ||
286 | "%02x:%02x:%02x:%02x:%02x:%02x:\n", | ||
287 | adapter->previousbssid[0], | ||
288 | adapter->previousbssid[1], | ||
289 | adapter->previousbssid[2], | ||
290 | adapter->previousbssid[3], | ||
291 | adapter->previousbssid[4], | ||
292 | adapter->previousbssid[5]); | ||
293 | |||
294 | i = libertas_find_SSID_in_list(adapter, | ||
295 | &adapter->previousssid, | ||
296 | adapter->previousbssid, | ||
297 | adapter->inframode); | ||
298 | |||
299 | if (i < 0) { | ||
300 | libertas_send_specific_BSSID_scan(priv, | ||
301 | adapter-> | ||
302 | previousbssid, | ||
303 | 1); | ||
304 | i = libertas_find_SSID_in_list(adapter, | ||
305 | &adapter-> | ||
306 | previousssid, | ||
307 | adapter-> | ||
308 | previousbssid, | ||
309 | adapter-> | ||
310 | inframode); | ||
311 | } | ||
312 | |||
313 | if (i < 0) { | ||
314 | /* If the BSSID could not be found, try just the SSID */ | ||
315 | i = libertas_find_SSID_in_list(adapter, | ||
316 | &adapter-> | ||
317 | previousssid, NULL, | ||
318 | adapter-> | ||
319 | inframode); | ||
320 | } | ||
321 | |||
322 | if (i < 0) { | ||
323 | libertas_send_specific_SSID_scan(priv, | ||
324 | &adapter-> | ||
325 | previousssid, | ||
326 | 1); | ||
327 | i = libertas_find_SSID_in_list(adapter, | ||
328 | &adapter-> | ||
329 | previousssid, NULL, | ||
330 | adapter-> | ||
331 | inframode); | ||
332 | } | ||
333 | |||
334 | if (i >= 0) { | ||
335 | ret = | ||
336 | wlan_associate(priv, | ||
337 | &adapter-> | ||
338 | scantable[i]); | ||
339 | } | ||
340 | } | ||
341 | } else if (adapter->inframode == wlan802_11ibss) { | ||
342 | ret = libertas_prepare_and_send_command(priv, | ||
343 | cmd_802_11_ad_hoc_start, | ||
344 | 0, | ||
345 | cmd_option_waitforrsp, | ||
346 | 0, &adapter->previousssid); | ||
347 | } | ||
348 | } | ||
349 | /* else it is connected */ | ||
350 | |||
351 | lbs_pr_debug(1, "\nwlanidle is off"); | ||
352 | LEAVE(); | ||
353 | return ret; | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * @brief Set Idle On | ||
358 | * | ||
359 | * @param priv A pointer to wlan_private structure | ||
360 | * @return 0 --success, otherwise fail | ||
361 | */ | ||
362 | int libertas_idle_on(wlan_private * priv) | ||
363 | { | ||
364 | wlan_adapter *adapter = priv->adapter; | ||
365 | int ret = 0; | ||
366 | |||
367 | if (adapter->connect_status == libertas_connected) { | ||
368 | if (adapter->inframode == wlan802_11infrastructure) { | ||
369 | lbs_pr_debug(1, "Previous SSID = %s\n", | ||
370 | adapter->previousssid.ssid); | ||
371 | memmove(&adapter->previousssid, | ||
372 | &adapter->curbssparams.ssid, | ||
373 | sizeof(struct WLAN_802_11_SSID)); | ||
374 | libertas_send_deauth(priv); | ||
375 | |||
376 | } else if (adapter->inframode == wlan802_11ibss) { | ||
377 | ret = libertas_stop_adhoc_network(priv); | ||
378 | } | ||
379 | |||
380 | } | ||
381 | |||
382 | lbs_pr_debug(1, "\nwlanidle is on"); | ||
383 | |||
384 | return ret; | ||
385 | } | ||
386 | |||
387 | /** | ||
388 | * @brief This function prepares command of authenticate. | ||
389 | * | ||
390 | * @param priv A pointer to wlan_private structure | ||
391 | * @param cmd A pointer to cmd_ds_command structure | ||
392 | * @param pdata_buf Void cast of pointer to a BSSID to authenticate with | ||
393 | * | ||
394 | * @return 0 or -1 | ||
395 | */ | ||
396 | int libertas_cmd_80211_authenticate(wlan_private * priv, | ||
397 | struct cmd_ds_command *cmd, | ||
398 | void *pdata_buf) | ||
399 | { | ||
400 | wlan_adapter *adapter = priv->adapter; | ||
401 | struct cmd_ds_802_11_authenticate *pauthenticate = | ||
402 | &cmd->params.auth; | ||
403 | u8 *bssid = pdata_buf; | ||
404 | |||
405 | cmd->command = cpu_to_le16(cmd_802_11_authenticate); | ||
406 | cmd->size = | ||
407 | cpu_to_le16(sizeof(struct cmd_ds_802_11_authenticate) | ||
408 | + S_DS_GEN); | ||
409 | |||
410 | pauthenticate->authtype = adapter->secinfo.authmode; | ||
411 | memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); | ||
412 | |||
413 | lbs_pr_debug(1, "AUTH_CMD: Bssid is : %x:%x:%x:%x:%x:%x\n", | ||
414 | bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]); | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | int libertas_cmd_80211_deauthenticate(wlan_private * priv, | ||
420 | struct cmd_ds_command *cmd) | ||
421 | { | ||
422 | wlan_adapter *adapter = priv->adapter; | ||
423 | struct cmd_ds_802_11_deauthenticate *dauth = &cmd->params.deauth; | ||
424 | |||
425 | ENTER(); | ||
426 | |||
427 | cmd->command = cpu_to_le16(cmd_802_11_deauthenticate); | ||
428 | cmd->size = | ||
429 | cpu_to_le16(sizeof(struct cmd_ds_802_11_deauthenticate) + | ||
430 | S_DS_GEN); | ||
431 | |||
432 | /* set AP MAC address */ | ||
433 | memmove(dauth->macaddr, adapter->curbssparams.bssid, | ||
434 | ETH_ALEN); | ||
435 | |||
436 | /* Reason code 3 = Station is leaving */ | ||
437 | #define REASON_CODE_STA_LEAVING 3 | ||
438 | dauth->reasoncode = cpu_to_le16(REASON_CODE_STA_LEAVING); | ||
439 | |||
440 | LEAVE(); | ||
441 | return 0; | ||
442 | } | ||
443 | |||
444 | int libertas_cmd_80211_associate(wlan_private * priv, | ||
445 | struct cmd_ds_command *cmd, void *pdata_buf) | ||
446 | { | ||
447 | wlan_adapter *adapter = priv->adapter; | ||
448 | struct cmd_ds_802_11_associate *passo = &cmd->params.associate; | ||
449 | int ret = 0; | ||
450 | struct bss_descriptor *pbssdesc; | ||
451 | u8 *card_rates; | ||
452 | u8 *pos; | ||
453 | int card_rates_size; | ||
454 | u16 tmpcap; | ||
455 | struct mrvlietypes_ssidparamset *ssid; | ||
456 | struct mrvlietypes_phyparamset *phy; | ||
457 | struct mrvlietypes_ssparamset *ss; | ||
458 | struct mrvlietypes_ratesparamset *rates; | ||
459 | struct mrvlietypes_rsnparamset *rsn; | ||
460 | |||
461 | ENTER(); | ||
462 | |||
463 | pbssdesc = pdata_buf; | ||
464 | pos = (u8 *) passo; | ||
465 | |||
466 | if (!adapter) { | ||
467 | ret = -1; | ||
468 | goto done; | ||
469 | } | ||
470 | |||
471 | cmd->command = cpu_to_le16(cmd_802_11_associate); | ||
472 | |||
473 | /* Save so we know which BSS Desc to use in the response handler */ | ||
474 | adapter->pattemptedbssdesc = pbssdesc; | ||
475 | |||
476 | memcpy(passo->peerstaaddr, | ||
477 | pbssdesc->macaddress, sizeof(passo->peerstaaddr)); | ||
478 | pos += sizeof(passo->peerstaaddr); | ||
479 | |||
480 | /* set the listen interval */ | ||
481 | passo->listeninterval = adapter->listeninterval; | ||
482 | |||
483 | pos += sizeof(passo->capinfo); | ||
484 | pos += sizeof(passo->listeninterval); | ||
485 | pos += sizeof(passo->bcnperiod); | ||
486 | pos += sizeof(passo->dtimperiod); | ||
487 | |||
488 | ssid = (struct mrvlietypes_ssidparamset *) pos; | ||
489 | ssid->header.type = cpu_to_le16(TLV_TYPE_SSID); | ||
490 | ssid->header.len = pbssdesc->ssid.ssidlength; | ||
491 | memcpy(ssid->ssid, pbssdesc->ssid.ssid, ssid->header.len); | ||
492 | pos += sizeof(ssid->header) + ssid->header.len; | ||
493 | ssid->header.len = cpu_to_le16(ssid->header.len); | ||
494 | |||
495 | phy = (struct mrvlietypes_phyparamset *) pos; | ||
496 | phy->header.type = cpu_to_le16(TLV_TYPE_PHY_DS); | ||
497 | phy->header.len = sizeof(phy->fh_ds.dsparamset); | ||
498 | memcpy(&phy->fh_ds.dsparamset, | ||
499 | &pbssdesc->phyparamset.dsparamset.currentchan, | ||
500 | sizeof(phy->fh_ds.dsparamset)); | ||
501 | pos += sizeof(phy->header) + phy->header.len; | ||
502 | phy->header.len = cpu_to_le16(phy->header.len); | ||
503 | |||
504 | ss = (struct mrvlietypes_ssparamset *) pos; | ||
505 | ss->header.type = cpu_to_le16(TLV_TYPE_CF); | ||
506 | ss->header.len = sizeof(ss->cf_ibss.cfparamset); | ||
507 | pos += sizeof(ss->header) + ss->header.len; | ||
508 | ss->header.len = cpu_to_le16(ss->header.len); | ||
509 | |||
510 | rates = (struct mrvlietypes_ratesparamset *) pos; | ||
511 | rates->header.type = cpu_to_le16(TLV_TYPE_RATES); | ||
512 | |||
513 | memcpy(&rates->rates, &pbssdesc->libertas_supported_rates, WLAN_SUPPORTED_RATES); | ||
514 | |||
515 | card_rates = libertas_supported_rates; | ||
516 | card_rates_size = sizeof(libertas_supported_rates); | ||
517 | |||
518 | if (get_common_rates(adapter, rates->rates, WLAN_SUPPORTED_RATES, | ||
519 | card_rates, card_rates_size)) { | ||
520 | ret = -1; | ||
521 | goto done; | ||
522 | } | ||
523 | |||
524 | rates->header.len = min_t(size_t, strlen(rates->rates), WLAN_SUPPORTED_RATES); | ||
525 | adapter->curbssparams.numofrates = rates->header.len; | ||
526 | |||
527 | pos += sizeof(rates->header) + rates->header.len; | ||
528 | rates->header.len = cpu_to_le16(rates->header.len); | ||
529 | |||
530 | if (adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { | ||
531 | rsn = (struct mrvlietypes_rsnparamset *) pos; | ||
532 | rsn->header.type = (u16) adapter->wpa_ie[0]; /* WPA_IE or WPA2_IE */ | ||
533 | rsn->header.type = cpu_to_le16(rsn->header.type); | ||
534 | rsn->header.len = (u16) adapter->wpa_ie[1]; | ||
535 | memcpy(rsn->rsnie, &adapter->wpa_ie[2], rsn->header.len); | ||
536 | lbs_dbg_hex("ASSOC_CMD: RSN IE", (u8 *) rsn, | ||
537 | sizeof(rsn->header) + rsn->header.len); | ||
538 | pos += sizeof(rsn->header) + rsn->header.len; | ||
539 | rsn->header.len = cpu_to_le16(rsn->header.len); | ||
540 | } | ||
541 | |||
542 | /* update curbssparams */ | ||
543 | adapter->curbssparams.channel = | ||
544 | (pbssdesc->phyparamset.dsparamset.currentchan); | ||
545 | |||
546 | /* Copy the infra. association rates into Current BSS state structure */ | ||
547 | memcpy(&adapter->curbssparams.datarates, &rates->rates, | ||
548 | min_t(size_t, sizeof(adapter->curbssparams.datarates), rates->header.len)); | ||
549 | |||
550 | lbs_pr_debug(1, "ASSOC_CMD: rates->header.len = %d\n", rates->header.len); | ||
551 | |||
552 | /* set IBSS field */ | ||
553 | if (pbssdesc->inframode == wlan802_11infrastructure) { | ||
554 | #define CAPINFO_ESS_MODE 1 | ||
555 | passo->capinfo.ess = CAPINFO_ESS_MODE; | ||
556 | } | ||
557 | |||
558 | if (libertas_parse_dnld_countryinfo_11d(priv)) { | ||
559 | ret = -1; | ||
560 | goto done; | ||
561 | } | ||
562 | |||
563 | cmd->size = cpu_to_le16((u16) (pos - (u8 *) passo) + S_DS_GEN); | ||
564 | |||
565 | /* set the capability info at last */ | ||
566 | memcpy(&tmpcap, &pbssdesc->cap, sizeof(passo->capinfo)); | ||
567 | tmpcap &= CAPINFO_MASK; | ||
568 | lbs_pr_debug(1, "ASSOC_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", | ||
569 | tmpcap, CAPINFO_MASK); | ||
570 | tmpcap = cpu_to_le16(tmpcap); | ||
571 | memcpy(&passo->capinfo, &tmpcap, sizeof(passo->capinfo)); | ||
572 | |||
573 | done: | ||
574 | LEAVE(); | ||
575 | return ret; | ||
576 | } | ||
577 | |||
578 | int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, | ||
579 | struct cmd_ds_command *cmd, void *pssid) | ||
580 | { | ||
581 | wlan_adapter *adapter = priv->adapter; | ||
582 | struct cmd_ds_802_11_ad_hoc_start *adhs = &cmd->params.ads; | ||
583 | int ret = 0; | ||
584 | int cmdappendsize = 0; | ||
585 | int i; | ||
586 | u16 tmpcap; | ||
587 | struct bss_descriptor *pbssdesc; | ||
588 | struct WLAN_802_11_SSID *ssid = pssid; | ||
589 | |||
590 | ENTER(); | ||
591 | |||
592 | if (!adapter) { | ||
593 | ret = -1; | ||
594 | goto done; | ||
595 | } | ||
596 | |||
597 | cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_start); | ||
598 | |||
599 | pbssdesc = &adapter->curbssparams.bssdescriptor; | ||
600 | adapter->pattemptedbssdesc = pbssdesc; | ||
601 | |||
602 | /* | ||
603 | * Fill in the parameters for 2 data structures: | ||
604 | * 1. cmd_ds_802_11_ad_hoc_start command | ||
605 | * 2. adapter->scantable[i] | ||
606 | * | ||
607 | * Driver will fill up SSID, bsstype,IBSS param, Physical Param, | ||
608 | * probe delay, and cap info. | ||
609 | * | ||
610 | * Firmware will fill up beacon period, DTIM, Basic rates | ||
611 | * and operational rates. | ||
612 | */ | ||
613 | |||
614 | memset(adhs->SSID, 0, IW_ESSID_MAX_SIZE); | ||
615 | |||
616 | memcpy(adhs->SSID, ssid->ssid, ssid->ssidlength); | ||
617 | |||
618 | lbs_pr_debug(1, "ADHOC_S_CMD: SSID = %s\n", adhs->SSID); | ||
619 | |||
620 | memset(pbssdesc->ssid.ssid, 0, IW_ESSID_MAX_SIZE); | ||
621 | memcpy(pbssdesc->ssid.ssid, ssid->ssid, ssid->ssidlength); | ||
622 | |||
623 | pbssdesc->ssid.ssidlength = ssid->ssidlength; | ||
624 | |||
625 | /* set the BSS type */ | ||
626 | adhs->bsstype = cmd_bss_type_ibss; | ||
627 | pbssdesc->inframode = wlan802_11ibss; | ||
628 | adhs->beaconperiod = adapter->beaconperiod; | ||
629 | |||
630 | /* set Physical param set */ | ||
631 | #define DS_PARA_IE_ID 3 | ||
632 | #define DS_PARA_IE_LEN 1 | ||
633 | |||
634 | adhs->phyparamset.dsparamset.elementid = DS_PARA_IE_ID; | ||
635 | adhs->phyparamset.dsparamset.len = DS_PARA_IE_LEN; | ||
636 | |||
637 | WARN_ON(!adapter->adhocchannel); | ||
638 | |||
639 | lbs_pr_debug(1, "ADHOC_S_CMD: Creating ADHOC on channel %d\n", | ||
640 | adapter->adhocchannel); | ||
641 | |||
642 | adapter->curbssparams.channel = adapter->adhocchannel; | ||
643 | |||
644 | pbssdesc->channel = adapter->adhocchannel; | ||
645 | adhs->phyparamset.dsparamset.currentchan = adapter->adhocchannel; | ||
646 | |||
647 | memcpy(&pbssdesc->phyparamset, | ||
648 | &adhs->phyparamset, sizeof(union ieeetypes_phyparamset)); | ||
649 | |||
650 | /* set IBSS param set */ | ||
651 | #define IBSS_PARA_IE_ID 6 | ||
652 | #define IBSS_PARA_IE_LEN 2 | ||
653 | |||
654 | adhs->ssparamset.ibssparamset.elementid = IBSS_PARA_IE_ID; | ||
655 | adhs->ssparamset.ibssparamset.len = IBSS_PARA_IE_LEN; | ||
656 | adhs->ssparamset.ibssparamset.atimwindow = adapter->atimwindow; | ||
657 | memcpy(&pbssdesc->ssparamset, | ||
658 | &adhs->ssparamset, sizeof(union IEEEtypes_ssparamset)); | ||
659 | |||
660 | /* set capability info */ | ||
661 | adhs->cap.ess = 0; | ||
662 | adhs->cap.ibss = 1; | ||
663 | pbssdesc->cap.ibss = 1; | ||
664 | |||
665 | /* probedelay */ | ||
666 | adhs->probedelay = cpu_to_le16(cmd_scan_probe_delay_time); | ||
667 | |||
668 | /* set up privacy in adapter->scantable[i] */ | ||
669 | if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) { | ||
670 | |||
671 | #define AD_HOC_CAP_PRIVACY_ON 1 | ||
672 | lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus set, privacy to WEP\n"); | ||
673 | pbssdesc->privacy = wlan802_11privfilter8021xWEP; | ||
674 | adhs->cap.privacy = AD_HOC_CAP_PRIVACY_ON; | ||
675 | } else { | ||
676 | lbs_pr_debug(1, "ADHOC_S_CMD: WEPstatus NOT set, Setting " | ||
677 | "privacy to ACCEPT ALL\n"); | ||
678 | pbssdesc->privacy = wlan802_11privfilteracceptall; | ||
679 | } | ||
680 | |||
681 | memset(adhs->datarate, 0, sizeof(adhs->datarate)); | ||
682 | |||
683 | if (adapter->adhoc_grate_enabled) { | ||
684 | memcpy(adhs->datarate, libertas_adhoc_rates_g, | ||
685 | min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_g))); | ||
686 | } else { | ||
687 | memcpy(adhs->datarate, libertas_adhoc_rates_b, | ||
688 | min(sizeof(adhs->datarate), sizeof(libertas_adhoc_rates_b))); | ||
689 | } | ||
690 | |||
691 | /* Find the last non zero */ | ||
692 | for (i = 0; i < sizeof(adhs->datarate) && adhs->datarate[i]; i++) ; | ||
693 | |||
694 | adapter->curbssparams.numofrates = i; | ||
695 | |||
696 | /* Copy the ad-hoc creating rates into Current BSS state structure */ | ||
697 | memcpy(&adapter->curbssparams.datarates, | ||
698 | &adhs->datarate, adapter->curbssparams.numofrates); | ||
699 | |||
700 | lbs_pr_debug(1, "ADHOC_S_CMD: rates=%02x %02x %02x %02x \n", | ||
701 | adhs->datarate[0], adhs->datarate[1], | ||
702 | adhs->datarate[2], adhs->datarate[3]); | ||
703 | |||
704 | lbs_pr_debug(1, "ADHOC_S_CMD: AD HOC Start command is ready\n"); | ||
705 | |||
706 | if (libertas_create_dnld_countryinfo_11d(priv)) { | ||
707 | lbs_pr_debug(1, "ADHOC_S_CMD: dnld_countryinfo_11d failed\n"); | ||
708 | ret = -1; | ||
709 | goto done; | ||
710 | } | ||
711 | |||
712 | cmd->size = | ||
713 | cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_start) | ||
714 | + S_DS_GEN + cmdappendsize); | ||
715 | |||
716 | memcpy(&tmpcap, &adhs->cap, sizeof(u16)); | ||
717 | tmpcap = cpu_to_le16(tmpcap); | ||
718 | memcpy(&adhs->cap, &tmpcap, sizeof(u16)); | ||
719 | |||
720 | ret = 0; | ||
721 | done: | ||
722 | LEAVE(); | ||
723 | return ret; | ||
724 | } | ||
725 | |||
726 | int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, | ||
727 | struct cmd_ds_command *cmd) | ||
728 | { | ||
729 | cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_stop); | ||
730 | cmd->size = cpu_to_le16(S_DS_GEN); | ||
731 | |||
732 | return 0; | ||
733 | } | ||
734 | |||
735 | int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, | ||
736 | struct cmd_ds_command *cmd, void *pdata_buf) | ||
737 | { | ||
738 | wlan_adapter *adapter = priv->adapter; | ||
739 | struct cmd_ds_802_11_ad_hoc_join *padhocjoin = &cmd->params.adj; | ||
740 | struct bss_descriptor *pbssdesc = pdata_buf; | ||
741 | int cmdappendsize = 0; | ||
742 | int ret = 0; | ||
743 | u8 *card_rates; | ||
744 | int card_rates_size; | ||
745 | u16 tmpcap; | ||
746 | int i; | ||
747 | |||
748 | ENTER(); | ||
749 | |||
750 | adapter->pattemptedbssdesc = pbssdesc; | ||
751 | |||
752 | cmd->command = cpu_to_le16(cmd_802_11_ad_hoc_join); | ||
753 | |||
754 | padhocjoin->bssdescriptor.bsstype = cmd_bss_type_ibss; | ||
755 | |||
756 | padhocjoin->bssdescriptor.beaconperiod = pbssdesc->beaconperiod; | ||
757 | |||
758 | memcpy(&padhocjoin->bssdescriptor.BSSID, | ||
759 | &pbssdesc->macaddress, ETH_ALEN); | ||
760 | |||
761 | memcpy(&padhocjoin->bssdescriptor.SSID, | ||
762 | &pbssdesc->ssid.ssid, pbssdesc->ssid.ssidlength); | ||
763 | |||
764 | memcpy(&padhocjoin->bssdescriptor.phyparamset, | ||
765 | &pbssdesc->phyparamset, sizeof(union ieeetypes_phyparamset)); | ||
766 | |||
767 | memcpy(&padhocjoin->bssdescriptor.ssparamset, | ||
768 | &pbssdesc->ssparamset, sizeof(union IEEEtypes_ssparamset)); | ||
769 | |||
770 | memcpy(&tmpcap, &pbssdesc->cap, sizeof(struct ieeetypes_capinfo)); | ||
771 | tmpcap &= CAPINFO_MASK; | ||
772 | |||
773 | lbs_pr_debug(1, "ADHOC_J_CMD: tmpcap=%4X CAPINFO_MASK=%4X\n", | ||
774 | tmpcap, CAPINFO_MASK); | ||
775 | memcpy(&padhocjoin->bssdescriptor.cap, &tmpcap, | ||
776 | sizeof(struct ieeetypes_capinfo)); | ||
777 | |||
778 | /* information on BSSID descriptor passed to FW */ | ||
779 | lbs_pr_debug(1, | ||
780 | "ADHOC_J_CMD: BSSID = %2x-%2x-%2x-%2x-%2x-%2x, SSID = %s\n", | ||
781 | padhocjoin->bssdescriptor.BSSID[0], | ||
782 | padhocjoin->bssdescriptor.BSSID[1], | ||
783 | padhocjoin->bssdescriptor.BSSID[2], | ||
784 | padhocjoin->bssdescriptor.BSSID[3], | ||
785 | padhocjoin->bssdescriptor.BSSID[4], | ||
786 | padhocjoin->bssdescriptor.BSSID[5], | ||
787 | padhocjoin->bssdescriptor.SSID); | ||
788 | |||
789 | lbs_pr_debug(1, "ADHOC_J_CMD: Data Rate = %x\n", | ||
790 | (u32) padhocjoin->bssdescriptor.datarates); | ||
791 | |||
792 | /* failtimeout */ | ||
793 | padhocjoin->failtimeout = cpu_to_le16(MRVDRV_ASSOCIATION_TIME_OUT); | ||
794 | |||
795 | /* probedelay */ | ||
796 | padhocjoin->probedelay = | ||
797 | cpu_to_le16(cmd_scan_probe_delay_time); | ||
798 | |||
799 | /* Copy Data rates from the rates recorded in scan response */ | ||
800 | memset(padhocjoin->bssdescriptor.datarates, 0, | ||
801 | sizeof(padhocjoin->bssdescriptor.datarates)); | ||
802 | memcpy(padhocjoin->bssdescriptor.datarates, pbssdesc->datarates, | ||
803 | min(sizeof(padhocjoin->bssdescriptor.datarates), | ||
804 | sizeof(pbssdesc->datarates))); | ||
805 | |||
806 | card_rates = libertas_supported_rates; | ||
807 | card_rates_size = sizeof(libertas_supported_rates); | ||
808 | |||
809 | adapter->curbssparams.channel = pbssdesc->channel; | ||
810 | |||
811 | if (get_common_rates(adapter, padhocjoin->bssdescriptor.datarates, | ||
812 | sizeof(padhocjoin->bssdescriptor.datarates), | ||
813 | card_rates, card_rates_size)) { | ||
814 | lbs_pr_debug(1, "ADHOC_J_CMD: get_common_rates returns error.\n"); | ||
815 | ret = -1; | ||
816 | goto done; | ||
817 | } | ||
818 | |||
819 | /* Find the last non zero */ | ||
820 | for (i = 0; i < sizeof(padhocjoin->bssdescriptor.datarates) | ||
821 | && padhocjoin->bssdescriptor.datarates[i]; i++) ; | ||
822 | |||
823 | adapter->curbssparams.numofrates = i; | ||
824 | |||
825 | /* | ||
826 | * Copy the adhoc joining rates to Current BSS State structure | ||
827 | */ | ||
828 | memcpy(adapter->curbssparams.datarates, | ||
829 | padhocjoin->bssdescriptor.datarates, | ||
830 | adapter->curbssparams.numofrates); | ||
831 | |||
832 | padhocjoin->bssdescriptor.ssparamset.ibssparamset.atimwindow = | ||
833 | cpu_to_le16(pbssdesc->atimwindow); | ||
834 | |||
835 | if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled) { | ||
836 | padhocjoin->bssdescriptor.cap.privacy = AD_HOC_CAP_PRIVACY_ON; | ||
837 | } | ||
838 | |||
839 | if (adapter->psmode == wlan802_11powermodemax_psp) { | ||
840 | /* wake up first */ | ||
841 | enum WLAN_802_11_POWER_MODE Localpsmode; | ||
842 | |||
843 | Localpsmode = wlan802_11powermodecam; | ||
844 | ret = libertas_prepare_and_send_command(priv, | ||
845 | cmd_802_11_ps_mode, | ||
846 | cmd_act_set, | ||
847 | 0, 0, &Localpsmode); | ||
848 | |||
849 | if (ret) { | ||
850 | ret = -1; | ||
851 | goto done; | ||
852 | } | ||
853 | } | ||
854 | |||
855 | if (libertas_parse_dnld_countryinfo_11d(priv)) { | ||
856 | ret = -1; | ||
857 | goto done; | ||
858 | } | ||
859 | |||
860 | cmd->size = | ||
861 | cpu_to_le16(sizeof(struct cmd_ds_802_11_ad_hoc_join) | ||
862 | + S_DS_GEN + cmdappendsize); | ||
863 | |||
864 | memcpy(&tmpcap, &padhocjoin->bssdescriptor.cap, | ||
865 | sizeof(struct ieeetypes_capinfo)); | ||
866 | tmpcap = cpu_to_le16(tmpcap); | ||
867 | |||
868 | memcpy(&padhocjoin->bssdescriptor.cap, | ||
869 | &tmpcap, sizeof(struct ieeetypes_capinfo)); | ||
870 | |||
871 | done: | ||
872 | LEAVE(); | ||
873 | return ret; | ||
874 | } | ||
875 | |||
876 | int libertas_ret_80211_associate(wlan_private * priv, | ||
877 | struct cmd_ds_command *resp) | ||
878 | { | ||
879 | wlan_adapter *adapter = priv->adapter; | ||
880 | int ret = 0; | ||
881 | union iwreq_data wrqu; | ||
882 | struct ieeetypes_assocrsp *passocrsp; | ||
883 | struct bss_descriptor *pbssdesc; | ||
884 | |||
885 | ENTER(); | ||
886 | |||
887 | passocrsp = (struct ieeetypes_assocrsp *) & resp->params; | ||
888 | |||
889 | if (passocrsp->statuscode) { | ||
890 | |||
891 | libertas_mac_event_disconnected(priv); | ||
892 | |||
893 | lbs_pr_debug(1, | ||
894 | "ASSOC_RESP: Association failed, status code = %d\n", | ||
895 | passocrsp->statuscode); | ||
896 | |||
897 | ret = -1; | ||
898 | goto done; | ||
899 | } | ||
900 | |||
901 | lbs_dbg_hex("ASSOC_RESP:", (void *)&resp->params, | ||
902 | le16_to_cpu(resp->size) - S_DS_GEN); | ||
903 | |||
904 | /* Send a Media Connected event, according to the Spec */ | ||
905 | adapter->connect_status = libertas_connected; | ||
906 | |||
907 | /* Set the attempted BSSID Index to current */ | ||
908 | pbssdesc = adapter->pattemptedbssdesc; | ||
909 | |||
910 | lbs_pr_debug(1, "ASSOC_RESP: %s\n", pbssdesc->ssid.ssid); | ||
911 | |||
912 | /* Set the new SSID to current SSID */ | ||
913 | memcpy(&adapter->curbssparams.ssid, | ||
914 | &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID)); | ||
915 | |||
916 | /* Set the new BSSID (AP's MAC address) to current BSSID */ | ||
917 | memcpy(adapter->curbssparams.bssid, | ||
918 | pbssdesc->macaddress, ETH_ALEN); | ||
919 | |||
920 | /* Make a copy of current BSSID descriptor */ | ||
921 | memcpy(&adapter->curbssparams.bssdescriptor, | ||
922 | pbssdesc, sizeof(struct bss_descriptor)); | ||
923 | |||
924 | lbs_pr_debug(1, "ASSOC_RESP: currentpacketfilter is %x\n", | ||
925 | adapter->currentpacketfilter); | ||
926 | |||
927 | adapter->SNR[TYPE_RXPD][TYPE_AVG] = 0; | ||
928 | adapter->NF[TYPE_RXPD][TYPE_AVG] = 0; | ||
929 | |||
930 | memset(adapter->rawSNR, 0x00, sizeof(adapter->rawSNR)); | ||
931 | memset(adapter->rawNF, 0x00, sizeof(adapter->rawNF)); | ||
932 | adapter->nextSNRNF = 0; | ||
933 | adapter->numSNRNF = 0; | ||
934 | |||
935 | netif_carrier_on(priv->wlan_dev.netdev); | ||
936 | netif_wake_queue(priv->wlan_dev.netdev); | ||
937 | |||
938 | lbs_pr_debug(1, "ASSOC_RESP: Associated \n"); | ||
939 | |||
940 | memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); | ||
941 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
942 | wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); | ||
943 | |||
944 | done: | ||
945 | LEAVE(); | ||
946 | return ret; | ||
947 | } | ||
948 | |||
949 | int libertas_ret_80211_disassociate(wlan_private * priv, | ||
950 | struct cmd_ds_command *resp) | ||
951 | { | ||
952 | ENTER(); | ||
953 | |||
954 | libertas_mac_event_disconnected(priv); | ||
955 | |||
956 | LEAVE(); | ||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | int libertas_ret_80211_ad_hoc_start(wlan_private * priv, | ||
961 | struct cmd_ds_command *resp) | ||
962 | { | ||
963 | wlan_adapter *adapter = priv->adapter; | ||
964 | int ret = 0; | ||
965 | u16 command = le16_to_cpu(resp->command); | ||
966 | u16 result = le16_to_cpu(resp->result); | ||
967 | struct cmd_ds_802_11_ad_hoc_result *padhocresult; | ||
968 | union iwreq_data wrqu; | ||
969 | struct bss_descriptor *pbssdesc; | ||
970 | |||
971 | ENTER(); | ||
972 | |||
973 | padhocresult = &resp->params.result; | ||
974 | |||
975 | lbs_pr_debug(1, "ADHOC_S_RESP: size = %d\n", le16_to_cpu(resp->size)); | ||
976 | lbs_pr_debug(1, "ADHOC_S_RESP: command = %x\n", command); | ||
977 | lbs_pr_debug(1, "ADHOC_S_RESP: result = %x\n", result); | ||
978 | |||
979 | pbssdesc = adapter->pattemptedbssdesc; | ||
980 | |||
981 | /* | ||
982 | * Join result code 0 --> SUCCESS | ||
983 | */ | ||
984 | if (result) { | ||
985 | lbs_pr_debug(1, "ADHOC_RESP failed\n"); | ||
986 | if (adapter->connect_status == libertas_connected) { | ||
987 | libertas_mac_event_disconnected(priv); | ||
988 | } | ||
989 | |||
990 | memset(&adapter->curbssparams.bssdescriptor, | ||
991 | 0x00, sizeof(adapter->curbssparams.bssdescriptor)); | ||
992 | |||
993 | LEAVE(); | ||
994 | return -1; | ||
995 | } | ||
996 | |||
997 | /* | ||
998 | * Now the join cmd should be successful | ||
999 | * If BSSID has changed use SSID to compare instead of BSSID | ||
1000 | */ | ||
1001 | lbs_pr_debug(1, "ADHOC_J_RESP %s\n", pbssdesc->ssid.ssid); | ||
1002 | |||
1003 | /* Send a Media Connected event, according to the Spec */ | ||
1004 | adapter->connect_status = libertas_connected; | ||
1005 | |||
1006 | if (command == cmd_ret_802_11_ad_hoc_start) { | ||
1007 | /* Update the created network descriptor with the new BSSID */ | ||
1008 | memcpy(pbssdesc->macaddress, | ||
1009 | padhocresult->BSSID, ETH_ALEN); | ||
1010 | } else { | ||
1011 | |||
1012 | /* Make a copy of current BSSID descriptor, only needed for join since | ||
1013 | * the current descriptor is already being used for adhoc start | ||
1014 | */ | ||
1015 | memmove(&adapter->curbssparams.bssdescriptor, | ||
1016 | pbssdesc, sizeof(struct bss_descriptor)); | ||
1017 | } | ||
1018 | |||
1019 | /* Set the BSSID from the joined/started descriptor */ | ||
1020 | memcpy(&adapter->curbssparams.bssid, | ||
1021 | pbssdesc->macaddress, ETH_ALEN); | ||
1022 | |||
1023 | /* Set the new SSID to current SSID */ | ||
1024 | memcpy(&adapter->curbssparams.ssid, | ||
1025 | &pbssdesc->ssid, sizeof(struct WLAN_802_11_SSID)); | ||
1026 | |||
1027 | netif_carrier_on(priv->wlan_dev.netdev); | ||
1028 | netif_wake_queue(priv->wlan_dev.netdev); | ||
1029 | |||
1030 | memset(&wrqu, 0, sizeof(wrqu)); | ||
1031 | memcpy(wrqu.ap_addr.sa_data, adapter->curbssparams.bssid, ETH_ALEN); | ||
1032 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
1033 | wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); | ||
1034 | |||
1035 | lbs_pr_debug(1, "ADHOC_RESP: - Joined/Started Ad Hoc\n"); | ||
1036 | lbs_pr_debug(1, "ADHOC_RESP: channel = %d\n", adapter->adhocchannel); | ||
1037 | lbs_pr_debug(1, "ADHOC_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1038 | padhocresult->BSSID[0], padhocresult->BSSID[1], | ||
1039 | padhocresult->BSSID[2], padhocresult->BSSID[3], | ||
1040 | padhocresult->BSSID[4], padhocresult->BSSID[5]); | ||
1041 | |||
1042 | LEAVE(); | ||
1043 | return ret; | ||
1044 | } | ||
1045 | |||
1046 | int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, | ||
1047 | struct cmd_ds_command *resp) | ||
1048 | { | ||
1049 | ENTER(); | ||
1050 | |||
1051 | libertas_mac_event_disconnected(priv); | ||
1052 | |||
1053 | LEAVE(); | ||
1054 | return 0; | ||
1055 | } | ||
diff --git a/drivers/net/wireless/libertas/join.h b/drivers/net/wireless/libertas/join.h new file mode 100644 index 000000000000..8efa2455af9a --- /dev/null +++ b/drivers/net/wireless/libertas/join.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ | ||
2 | /* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ | ||
3 | |||
4 | /** | ||
5 | * Interface for the wlan infrastructure and adhoc join routines | ||
6 | * | ||
7 | * Driver interface functions and type declarations for the join module | ||
8 | * implemented in wlan_join.c. Process all start/join requests for | ||
9 | * both adhoc and infrastructure networks | ||
10 | */ | ||
11 | #ifndef _WLAN_JOIN_H | ||
12 | #define _WLAN_JOIN_H | ||
13 | |||
14 | #include "defs.h" | ||
15 | |||
16 | struct cmd_ds_command; | ||
17 | extern int libertas_cmd_80211_authenticate(wlan_private * priv, | ||
18 | struct cmd_ds_command *cmd, | ||
19 | void *pdata_buf); | ||
20 | extern int libertas_cmd_80211_ad_hoc_join(wlan_private * priv, | ||
21 | struct cmd_ds_command *cmd, | ||
22 | void *pdata_buf); | ||
23 | extern int libertas_cmd_80211_ad_hoc_stop(wlan_private * priv, | ||
24 | struct cmd_ds_command *cmd); | ||
25 | extern int libertas_cmd_80211_ad_hoc_start(wlan_private * priv, | ||
26 | struct cmd_ds_command *cmd, | ||
27 | void *pssid); | ||
28 | extern int libertas_cmd_80211_deauthenticate(wlan_private * priv, | ||
29 | struct cmd_ds_command *cmd); | ||
30 | extern int libertas_cmd_80211_associate(wlan_private * priv, | ||
31 | struct cmd_ds_command *cmd, | ||
32 | void *pdata_buf); | ||
33 | |||
34 | extern int libertas_ret_80211_ad_hoc_start(wlan_private * priv, | ||
35 | struct cmd_ds_command *resp); | ||
36 | extern int libertas_ret_80211_ad_hoc_stop(wlan_private * priv, | ||
37 | struct cmd_ds_command *resp); | ||
38 | extern int libertas_ret_80211_disassociate(wlan_private * priv, | ||
39 | struct cmd_ds_command *resp); | ||
40 | extern int libertas_ret_80211_associate(wlan_private * priv, | ||
41 | struct cmd_ds_command *resp); | ||
42 | |||
43 | extern int libertas_idle_on(wlan_private * priv); | ||
44 | extern int libertas_idle_off(wlan_private * priv); | ||
45 | |||
46 | extern int libertas_do_adhocstop_ioctl(wlan_private * priv); | ||
47 | extern int libertas_reassociation_thread(void *data); | ||
48 | |||
49 | struct WLAN_802_11_SSID; | ||
50 | struct bss_descriptor; | ||
51 | |||
52 | extern int libertas_start_adhoc_network(wlan_private * priv, | ||
53 | struct WLAN_802_11_SSID *adhocssid); | ||
54 | extern int libertas_join_adhoc_network(wlan_private * priv, struct bss_descriptor *pbssdesc); | ||
55 | extern int libertas_stop_adhoc_network(wlan_private * priv); | ||
56 | |||
57 | extern int libertas_send_deauthentication(wlan_private * priv); | ||
58 | extern int libertas_send_deauth(wlan_private * priv); | ||
59 | |||
60 | extern int libertas_do_adhocstop_ioctl(wlan_private * priv); | ||
61 | |||
62 | int wlan_associate(wlan_private * priv, struct bss_descriptor * pbssdesc); | ||
63 | |||
64 | #endif | ||
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c new file mode 100644 index 000000000000..dcbf102a057e --- /dev/null +++ b/drivers/net/wireless/libertas/main.c | |||
@@ -0,0 +1,1258 @@ | |||
1 | /** | ||
2 | * This file contains the major functions in WLAN | ||
3 | * driver. It includes init, exit, open, close and main | ||
4 | * thread etc.. | ||
5 | */ | ||
6 | |||
7 | #include <linux/delay.h> | ||
8 | #include <linux/freezer.h> | ||
9 | #include <linux/etherdevice.h> | ||
10 | #include <linux/netdevice.h> | ||
11 | #include <linux/if_arp.h> | ||
12 | |||
13 | #include <net/iw_handler.h> | ||
14 | |||
15 | #include "host.h" | ||
16 | #include "sbi.h" | ||
17 | #include "decl.h" | ||
18 | #include "dev.h" | ||
19 | #include "fw.h" | ||
20 | #include "wext.h" | ||
21 | #include "debugfs.h" | ||
22 | #include "assoc.h" | ||
23 | |||
24 | #ifdef ENABLE_PM | ||
25 | static struct pm_dev *wlan_pm_dev = NULL; | ||
26 | #endif | ||
27 | |||
28 | #define WLAN_TX_PWR_DEFAULT 20 /*100mW */ | ||
29 | #define WLAN_TX_PWR_US_DEFAULT 20 /*100mW */ | ||
30 | #define WLAN_TX_PWR_JP_DEFAULT 16 /*50mW */ | ||
31 | #define WLAN_TX_PWR_FR_DEFAULT 20 /*100mW */ | ||
32 | #define WLAN_TX_PWR_EMEA_DEFAULT 20 /*100mW */ | ||
33 | |||
34 | /* Format { channel, frequency (MHz), maxtxpower } */ | ||
35 | /* band: 'B/G', region: USA FCC/Canada IC */ | ||
36 | static struct chan_freq_power channel_freq_power_US_BG[] = { | ||
37 | {1, 2412, WLAN_TX_PWR_US_DEFAULT}, | ||
38 | {2, 2417, WLAN_TX_PWR_US_DEFAULT}, | ||
39 | {3, 2422, WLAN_TX_PWR_US_DEFAULT}, | ||
40 | {4, 2427, WLAN_TX_PWR_US_DEFAULT}, | ||
41 | {5, 2432, WLAN_TX_PWR_US_DEFAULT}, | ||
42 | {6, 2437, WLAN_TX_PWR_US_DEFAULT}, | ||
43 | {7, 2442, WLAN_TX_PWR_US_DEFAULT}, | ||
44 | {8, 2447, WLAN_TX_PWR_US_DEFAULT}, | ||
45 | {9, 2452, WLAN_TX_PWR_US_DEFAULT}, | ||
46 | {10, 2457, WLAN_TX_PWR_US_DEFAULT}, | ||
47 | {11, 2462, WLAN_TX_PWR_US_DEFAULT} | ||
48 | }; | ||
49 | |||
50 | /* band: 'B/G', region: Europe ETSI */ | ||
51 | static struct chan_freq_power channel_freq_power_EU_BG[] = { | ||
52 | {1, 2412, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
53 | {2, 2417, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
54 | {3, 2422, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
55 | {4, 2427, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
56 | {5, 2432, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
57 | {6, 2437, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
58 | {7, 2442, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
59 | {8, 2447, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
60 | {9, 2452, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
61 | {10, 2457, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
62 | {11, 2462, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
63 | {12, 2467, WLAN_TX_PWR_EMEA_DEFAULT}, | ||
64 | {13, 2472, WLAN_TX_PWR_EMEA_DEFAULT} | ||
65 | }; | ||
66 | |||
67 | /* band: 'B/G', region: Spain */ | ||
68 | static struct chan_freq_power channel_freq_power_SPN_BG[] = { | ||
69 | {10, 2457, WLAN_TX_PWR_DEFAULT}, | ||
70 | {11, 2462, WLAN_TX_PWR_DEFAULT} | ||
71 | }; | ||
72 | |||
73 | /* band: 'B/G', region: France */ | ||
74 | static struct chan_freq_power channel_freq_power_FR_BG[] = { | ||
75 | {10, 2457, WLAN_TX_PWR_FR_DEFAULT}, | ||
76 | {11, 2462, WLAN_TX_PWR_FR_DEFAULT}, | ||
77 | {12, 2467, WLAN_TX_PWR_FR_DEFAULT}, | ||
78 | {13, 2472, WLAN_TX_PWR_FR_DEFAULT} | ||
79 | }; | ||
80 | |||
81 | /* band: 'B/G', region: Japan */ | ||
82 | static struct chan_freq_power channel_freq_power_JPN_BG[] = { | ||
83 | {1, 2412, WLAN_TX_PWR_JP_DEFAULT}, | ||
84 | {2, 2417, WLAN_TX_PWR_JP_DEFAULT}, | ||
85 | {3, 2422, WLAN_TX_PWR_JP_DEFAULT}, | ||
86 | {4, 2427, WLAN_TX_PWR_JP_DEFAULT}, | ||
87 | {5, 2432, WLAN_TX_PWR_JP_DEFAULT}, | ||
88 | {6, 2437, WLAN_TX_PWR_JP_DEFAULT}, | ||
89 | {7, 2442, WLAN_TX_PWR_JP_DEFAULT}, | ||
90 | {8, 2447, WLAN_TX_PWR_JP_DEFAULT}, | ||
91 | {9, 2452, WLAN_TX_PWR_JP_DEFAULT}, | ||
92 | {10, 2457, WLAN_TX_PWR_JP_DEFAULT}, | ||
93 | {11, 2462, WLAN_TX_PWR_JP_DEFAULT}, | ||
94 | {12, 2467, WLAN_TX_PWR_JP_DEFAULT}, | ||
95 | {13, 2472, WLAN_TX_PWR_JP_DEFAULT}, | ||
96 | {14, 2484, WLAN_TX_PWR_JP_DEFAULT} | ||
97 | }; | ||
98 | |||
99 | /** | ||
100 | * the structure for channel, frequency and power | ||
101 | */ | ||
102 | struct region_cfp_table { | ||
103 | u8 region; | ||
104 | struct chan_freq_power *cfp_BG; | ||
105 | int cfp_no_BG; | ||
106 | }; | ||
107 | |||
108 | /** | ||
109 | * the structure for the mapping between region and CFP | ||
110 | */ | ||
111 | static struct region_cfp_table region_cfp_table[] = { | ||
112 | {0x10, /*US FCC */ | ||
113 | channel_freq_power_US_BG, | ||
114 | sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), | ||
115 | } | ||
116 | , | ||
117 | {0x20, /*CANADA IC */ | ||
118 | channel_freq_power_US_BG, | ||
119 | sizeof(channel_freq_power_US_BG) / sizeof(struct chan_freq_power), | ||
120 | } | ||
121 | , | ||
122 | {0x30, /*EU*/ channel_freq_power_EU_BG, | ||
123 | sizeof(channel_freq_power_EU_BG) / sizeof(struct chan_freq_power), | ||
124 | } | ||
125 | , | ||
126 | {0x31, /*SPAIN*/ channel_freq_power_SPN_BG, | ||
127 | sizeof(channel_freq_power_SPN_BG) / sizeof(struct chan_freq_power), | ||
128 | } | ||
129 | , | ||
130 | {0x32, /*FRANCE*/ channel_freq_power_FR_BG, | ||
131 | sizeof(channel_freq_power_FR_BG) / sizeof(struct chan_freq_power), | ||
132 | } | ||
133 | , | ||
134 | {0x40, /*JAPAN*/ channel_freq_power_JPN_BG, | ||
135 | sizeof(channel_freq_power_JPN_BG) / sizeof(struct chan_freq_power), | ||
136 | } | ||
137 | , | ||
138 | /*Add new region here */ | ||
139 | }; | ||
140 | |||
141 | /** | ||
142 | * the rates supported by the card | ||
143 | */ | ||
144 | u8 libertas_wlan_data_rates[WLAN_SUPPORTED_RATES] = | ||
145 | { 0x02, 0x04, 0x0B, 0x16, 0x00, 0x0C, 0x12, | ||
146 | 0x18, 0x24, 0x30, 0x48, 0x60, 0x6C, 0x00 | ||
147 | }; | ||
148 | |||
149 | /** | ||
150 | * the rates supported | ||
151 | */ | ||
152 | u8 libertas_supported_rates[G_SUPPORTED_RATES] = | ||
153 | { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, | ||
154 | 0 }; | ||
155 | |||
156 | /** | ||
157 | * the rates supported for ad-hoc G mode | ||
158 | */ | ||
159 | u8 libertas_adhoc_rates_g[G_SUPPORTED_RATES] = | ||
160 | { 0x82, 0x84, 0x8b, 0x96, 0x0c, 0x12, 0x18, 0x24, 0x30, 0x48, 0x60, 0x6c, | ||
161 | 0 }; | ||
162 | |||
163 | /** | ||
164 | * the rates supported for ad-hoc B mode | ||
165 | */ | ||
166 | u8 libertas_adhoc_rates_b[4] = { 0x82, 0x84, 0x8b, 0x96 }; | ||
167 | |||
168 | /** | ||
169 | * the global variable of a pointer to wlan_private | ||
170 | * structure variable | ||
171 | */ | ||
172 | static wlan_private *wlanpriv = NULL; | ||
173 | |||
174 | #define MAX_DEVS 5 | ||
175 | static struct net_device *libertas_devs[MAX_DEVS]; | ||
176 | static int libertas_found = 0; | ||
177 | |||
178 | /** | ||
179 | * the table to keep region code | ||
180 | */ | ||
181 | u16 libertas_region_code_to_index[MRVDRV_MAX_REGION_CODE] = | ||
182 | { 0x10, 0x20, 0x30, 0x31, 0x32, 0x40 }; | ||
183 | |||
184 | static u8 *default_fw_name = "usb8388.bin"; | ||
185 | |||
186 | /** | ||
187 | * Attributes exported through sysfs | ||
188 | */ | ||
189 | |||
190 | /** | ||
191 | * @brief Get function for sysfs attribute libertas_mpp | ||
192 | */ | ||
193 | static ssize_t libertas_mpp_get(struct device * dev, | ||
194 | struct device_attribute *attr, char * buf) { | ||
195 | struct cmd_ds_mesh_access mesh_access; | ||
196 | |||
197 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
198 | libertas_prepare_and_send_command(to_net_dev(dev)->priv, | ||
199 | cmd_mesh_access, | ||
200 | cmd_act_mesh_get_mpp, | ||
201 | cmd_option_waitforrsp, 0, (void *)&mesh_access); | ||
202 | |||
203 | return snprintf(buf, 3, "%d\n", mesh_access.data[0]); | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * @brief Set function for sysfs attribute libertas_mpp | ||
208 | */ | ||
209 | static ssize_t libertas_mpp_set(struct device * dev, | ||
210 | struct device_attribute *attr, const char * buf, size_t count) { | ||
211 | struct cmd_ds_mesh_access mesh_access; | ||
212 | |||
213 | |||
214 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
215 | sscanf(buf, "%d", &(mesh_access.data[0])); | ||
216 | libertas_prepare_and_send_command((to_net_dev(dev))->priv, | ||
217 | cmd_mesh_access, | ||
218 | cmd_act_mesh_set_mpp, | ||
219 | cmd_option_waitforrsp, 0, (void *)&mesh_access); | ||
220 | return strlen(buf); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * libertas_mpp attribute to be exported per mshX interface | ||
225 | * through sysfs (/sys/class/net/mshX/libertas-mpp) | ||
226 | */ | ||
227 | static DEVICE_ATTR(libertas_mpp, 0644, libertas_mpp_get, | ||
228 | libertas_mpp_set ); | ||
229 | |||
230 | /** | ||
231 | * @brief Check if the device can be open and wait if necessary. | ||
232 | * | ||
233 | * @param dev A pointer to net_device structure | ||
234 | * @return 0 | ||
235 | * | ||
236 | * For USB adapter, on some systems the device open handler will be | ||
237 | * called before FW ready. Use the following flag check and wait | ||
238 | * function to work around the issue. | ||
239 | * | ||
240 | */ | ||
241 | static int pre_open_check(struct net_device *dev) { | ||
242 | wlan_private *priv = (wlan_private *) dev->priv; | ||
243 | wlan_adapter *adapter = priv->adapter; | ||
244 | int i = 0; | ||
245 | |||
246 | while (!adapter->fw_ready && i < 20) { | ||
247 | i++; | ||
248 | msleep_interruptible(100); | ||
249 | } | ||
250 | if (!adapter->fw_ready) { | ||
251 | lbs_pr_info("FW not ready, pre_open_check() return failure\n"); | ||
252 | LEAVE(); | ||
253 | return -1; | ||
254 | } | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * @brief This function opens the device | ||
261 | * | ||
262 | * @param dev A pointer to net_device structure | ||
263 | * @return 0 | ||
264 | */ | ||
265 | static int wlan_dev_open(struct net_device *dev) | ||
266 | { | ||
267 | wlan_private *priv = (wlan_private *) dev->priv; | ||
268 | wlan_adapter *adapter = priv->adapter; | ||
269 | |||
270 | ENTER(); | ||
271 | |||
272 | |||
273 | priv->open = 1; | ||
274 | |||
275 | if (adapter->connect_status == libertas_connected) { | ||
276 | netif_carrier_on(priv->wlan_dev.netdev); | ||
277 | } else | ||
278 | netif_carrier_off(priv->wlan_dev.netdev); | ||
279 | |||
280 | LEAVE(); | ||
281 | return 0; | ||
282 | } | ||
283 | /** | ||
284 | * @brief This function opens the mshX interface | ||
285 | * | ||
286 | * @param dev A pointer to net_device structure | ||
287 | * @return 0 | ||
288 | */ | ||
289 | static int mesh_open(struct net_device *dev) | ||
290 | { | ||
291 | wlan_private *priv = (wlan_private *) dev->priv ; | ||
292 | |||
293 | if(pre_open_check(dev) == -1) | ||
294 | return -1; | ||
295 | priv->mesh_open = 1 ; | ||
296 | netif_start_queue(priv->mesh_dev); | ||
297 | if (priv->infra_open == 0) | ||
298 | return wlan_dev_open(priv->wlan_dev.netdev) ; | ||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /** | ||
303 | * @brief This function opens the ethX interface | ||
304 | * | ||
305 | * @param dev A pointer to net_device structure | ||
306 | * @return 0 | ||
307 | */ | ||
308 | static int wlan_open(struct net_device *dev) | ||
309 | { | ||
310 | wlan_private *priv = (wlan_private *) dev->priv ; | ||
311 | |||
312 | if(pre_open_check(dev) == -1) | ||
313 | return -1; | ||
314 | priv->infra_open = 1 ; | ||
315 | netif_wake_queue(priv->wlan_dev.netdev); | ||
316 | if (priv->open == 0) | ||
317 | return wlan_dev_open(priv->wlan_dev.netdev) ; | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int wlan_dev_close(struct net_device *dev) | ||
322 | { | ||
323 | wlan_private *priv = dev->priv; | ||
324 | |||
325 | ENTER(); | ||
326 | |||
327 | netif_carrier_off(priv->wlan_dev.netdev); | ||
328 | priv->open = 0; | ||
329 | |||
330 | LEAVE(); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | /** | ||
335 | * @brief This function closes the mshX interface | ||
336 | * | ||
337 | * @param dev A pointer to net_device structure | ||
338 | * @return 0 | ||
339 | */ | ||
340 | static int mesh_close(struct net_device *dev) | ||
341 | { | ||
342 | wlan_private *priv = (wlan_private *) (dev->priv); | ||
343 | |||
344 | priv->mesh_open = 0; | ||
345 | netif_stop_queue(priv->mesh_dev); | ||
346 | if (priv->infra_open == 0) | ||
347 | return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ; | ||
348 | else | ||
349 | return 0; | ||
350 | } | ||
351 | |||
352 | /** | ||
353 | * @brief This function closes the ethX interface | ||
354 | * | ||
355 | * @param dev A pointer to net_device structure | ||
356 | * @return 0 | ||
357 | */ | ||
358 | static int wlan_close(struct net_device *dev) { | ||
359 | wlan_private *priv = (wlan_private *) dev->priv; | ||
360 | |||
361 | netif_stop_queue(priv->wlan_dev.netdev); | ||
362 | priv->infra_open = 0; | ||
363 | if (priv->mesh_open == 0) | ||
364 | return wlan_dev_close( ((wlan_private *) dev->priv)->wlan_dev.netdev) ; | ||
365 | else | ||
366 | return 0; | ||
367 | } | ||
368 | |||
369 | |||
370 | #ifdef ENABLE_PM | ||
371 | |||
372 | /** | ||
373 | * @brief This function is a callback function. it is called by | ||
374 | * kernel to enter or exit power saving mode. | ||
375 | * | ||
376 | * @param pmdev A pointer to pm_dev | ||
377 | * @param pmreq pm_request_t | ||
378 | * @param pmdata A pointer to pmdata | ||
379 | * @return 0 or -1 | ||
380 | */ | ||
381 | static int wlan_pm_callback(struct pm_dev *pmdev, pm_request_t pmreq, | ||
382 | void *pmdata) | ||
383 | { | ||
384 | wlan_private *priv = wlanpriv; | ||
385 | wlan_adapter *adapter = priv->adapter; | ||
386 | struct net_device *dev = priv->wlan_dev.netdev; | ||
387 | |||
388 | lbs_pr_debug(1, "WPRM_PM_CALLBACK: pmreq = %d.\n", pmreq); | ||
389 | |||
390 | switch (pmreq) { | ||
391 | case PM_SUSPEND: | ||
392 | lbs_pr_debug(1, "WPRM_PM_CALLBACK: enter PM_SUSPEND.\n"); | ||
393 | |||
394 | /* in associated mode */ | ||
395 | if (adapter->connect_status == libertas_connected) { | ||
396 | if ((adapter->psstate != PS_STATE_SLEEP) | ||
397 | ) { | ||
398 | lbs_pr_debug(1, | ||
399 | "wlan_pm_callback: can't enter sleep mode\n"); | ||
400 | return -1; | ||
401 | } else { | ||
402 | |||
403 | /* | ||
404 | * Detach the network interface | ||
405 | * if the network is running | ||
406 | */ | ||
407 | if (netif_running(dev)) { | ||
408 | netif_device_detach(dev); | ||
409 | lbs_pr_debug(1, | ||
410 | "netif_device_detach().\n"); | ||
411 | } | ||
412 | libertas_sbi_suspend(priv); | ||
413 | } | ||
414 | break; | ||
415 | } | ||
416 | |||
417 | /* in non associated mode */ | ||
418 | |||
419 | /* | ||
420 | * Detach the network interface | ||
421 | * if the network is running | ||
422 | */ | ||
423 | if (netif_running(dev)) | ||
424 | netif_device_detach(dev); | ||
425 | |||
426 | /* | ||
427 | * Storing and restoring of the regs be taken care | ||
428 | * at the driver rest will be done at wlan driver | ||
429 | * this makes driver independent of the card | ||
430 | */ | ||
431 | |||
432 | libertas_sbi_suspend(priv); | ||
433 | |||
434 | break; | ||
435 | |||
436 | case PM_RESUME: | ||
437 | /* in associated mode */ | ||
438 | if (adapter->connect_status == libertas_connected) { | ||
439 | { | ||
440 | /* | ||
441 | * Bring the inteface up first | ||
442 | * This case should not happen still ... | ||
443 | */ | ||
444 | libertas_sbi_resume(priv); | ||
445 | |||
446 | /* | ||
447 | * Attach the network interface | ||
448 | * if the network is running | ||
449 | */ | ||
450 | if (netif_running(dev)) { | ||
451 | netif_device_attach(dev); | ||
452 | lbs_pr_debug(1, | ||
453 | "after netif_device_attach().\n"); | ||
454 | } | ||
455 | lbs_pr_debug(1, | ||
456 | "After netif attach, in associated mode.\n"); | ||
457 | } | ||
458 | break; | ||
459 | } | ||
460 | |||
461 | /* in non associated mode */ | ||
462 | |||
463 | /* | ||
464 | * Bring the inteface up first | ||
465 | * This case should not happen still ... | ||
466 | */ | ||
467 | |||
468 | libertas_sbi_resume(priv); | ||
469 | |||
470 | if (netif_running(dev)) | ||
471 | netif_device_attach(dev); | ||
472 | |||
473 | lbs_pr_debug(1, "after netif attach, in NON associated mode.\n"); | ||
474 | break; | ||
475 | } | ||
476 | |||
477 | return 0; | ||
478 | } | ||
479 | #endif /* ENABLE_PM */ | ||
480 | |||
481 | static int wlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
482 | { | ||
483 | int ret = 0; | ||
484 | wlan_private *priv = dev->priv; | ||
485 | |||
486 | ENTER(); | ||
487 | |||
488 | if (priv->wlan_dev.dnld_sent || priv->adapter->TxLockFlag) { | ||
489 | priv->stats.tx_dropped++; | ||
490 | goto done; | ||
491 | } | ||
492 | |||
493 | netif_stop_queue(priv->wlan_dev.netdev); | ||
494 | |||
495 | if (libertas_process_tx(priv, skb) == 0) | ||
496 | dev->trans_start = jiffies; | ||
497 | done: | ||
498 | LEAVE(); | ||
499 | return ret; | ||
500 | } | ||
501 | |||
502 | /** | ||
503 | * @brief Mark mesh packets and handover them to wlan_hard_start_xmit | ||
504 | * | ||
505 | */ | ||
506 | static int mesh_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
507 | { | ||
508 | wlan_private *priv = dev->priv; | ||
509 | ENTER(); | ||
510 | SET_MESH_FRAME(skb); | ||
511 | LEAVE(); | ||
512 | |||
513 | return wlan_hard_start_xmit(skb, priv->wlan_dev.netdev); | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * @brief Mark non-mesh packets and handover them to wlan_hard_start_xmit | ||
518 | * | ||
519 | */ | ||
520 | static int wlan_pre_start_xmit(struct sk_buff *skb, struct net_device *dev) { | ||
521 | ENTER(); | ||
522 | UNSET_MESH_FRAME(skb); | ||
523 | LEAVE(); | ||
524 | return wlan_hard_start_xmit(skb, dev); | ||
525 | } | ||
526 | |||
527 | static void wlan_tx_timeout(struct net_device *dev) | ||
528 | { | ||
529 | wlan_private *priv = (wlan_private *) dev->priv; | ||
530 | |||
531 | ENTER(); | ||
532 | |||
533 | lbs_pr_err("tx watch dog timeout!\n"); | ||
534 | |||
535 | priv->wlan_dev.dnld_sent = DNLD_RES_RECEIVED; | ||
536 | dev->trans_start = jiffies; | ||
537 | |||
538 | if (priv->adapter->currenttxskb) { | ||
539 | if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { | ||
540 | /* If we are here, we have not received feedback from | ||
541 | the previous packet. Assume TX_FAIL and move on. */ | ||
542 | priv->adapter->eventcause = 0x01000000; | ||
543 | libertas_send_tx_feedback(priv); | ||
544 | } else | ||
545 | wake_up_interruptible(&priv->mainthread.waitq); | ||
546 | } else if (priv->adapter->connect_status == libertas_connected) | ||
547 | netif_wake_queue(priv->wlan_dev.netdev); | ||
548 | |||
549 | LEAVE(); | ||
550 | } | ||
551 | |||
552 | /** | ||
553 | * @brief This function returns the network statistics | ||
554 | * | ||
555 | * @param dev A pointer to wlan_private structure | ||
556 | * @return A pointer to net_device_stats structure | ||
557 | */ | ||
558 | static struct net_device_stats *wlan_get_stats(struct net_device *dev) | ||
559 | { | ||
560 | wlan_private *priv = (wlan_private *) dev->priv; | ||
561 | |||
562 | return &priv->stats; | ||
563 | } | ||
564 | |||
565 | static int wlan_set_mac_address(struct net_device *dev, void *addr) | ||
566 | { | ||
567 | int ret = 0; | ||
568 | wlan_private *priv = (wlan_private *) dev->priv; | ||
569 | wlan_adapter *adapter = priv->adapter; | ||
570 | struct sockaddr *phwaddr = addr; | ||
571 | |||
572 | ENTER(); | ||
573 | |||
574 | memset(adapter->current_addr, 0, ETH_ALEN); | ||
575 | |||
576 | /* dev->dev_addr is 8 bytes */ | ||
577 | lbs_dbg_hex("dev->dev_addr:", dev->dev_addr, ETH_ALEN); | ||
578 | |||
579 | lbs_dbg_hex("addr:", phwaddr->sa_data, ETH_ALEN); | ||
580 | memcpy(adapter->current_addr, phwaddr->sa_data, ETH_ALEN); | ||
581 | |||
582 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_mac_address, | ||
583 | cmd_act_set, | ||
584 | cmd_option_waitforrsp, 0, NULL); | ||
585 | |||
586 | if (ret) { | ||
587 | lbs_pr_debug(1, "set mac address failed.\n"); | ||
588 | ret = -1; | ||
589 | goto done; | ||
590 | } | ||
591 | |||
592 | lbs_dbg_hex("adapter->macaddr:", adapter->current_addr, ETH_ALEN); | ||
593 | memcpy(dev->dev_addr, adapter->current_addr, ETH_ALEN); | ||
594 | memcpy(((wlan_private *) dev->priv)->mesh_dev->dev_addr, adapter->current_addr, ETH_ALEN); | ||
595 | |||
596 | done: | ||
597 | LEAVE(); | ||
598 | return ret; | ||
599 | } | ||
600 | |||
601 | static int wlan_copy_multicast_address(wlan_adapter * adapter, | ||
602 | struct net_device *dev) | ||
603 | { | ||
604 | int i = 0; | ||
605 | struct dev_mc_list *mcptr = dev->mc_list; | ||
606 | |||
607 | for (i = 0; i < dev->mc_count; i++) { | ||
608 | memcpy(&adapter->multicastlist[i], mcptr->dmi_addr, ETH_ALEN); | ||
609 | mcptr = mcptr->next; | ||
610 | } | ||
611 | |||
612 | return i; | ||
613 | |||
614 | } | ||
615 | |||
616 | static void wlan_set_multicast_list(struct net_device *dev) | ||
617 | { | ||
618 | wlan_private *priv = dev->priv; | ||
619 | wlan_adapter *adapter = priv->adapter; | ||
620 | int oldpacketfilter; | ||
621 | |||
622 | ENTER(); | ||
623 | |||
624 | oldpacketfilter = adapter->currentpacketfilter; | ||
625 | |||
626 | if (dev->flags & IFF_PROMISC) { | ||
627 | lbs_pr_debug(1, "enable Promiscuous mode\n"); | ||
628 | adapter->currentpacketfilter |= | ||
629 | cmd_act_mac_promiscuous_enable; | ||
630 | adapter->currentpacketfilter &= | ||
631 | ~(cmd_act_mac_all_multicast_enable | | ||
632 | cmd_act_mac_multicast_enable); | ||
633 | } else { | ||
634 | /* Multicast */ | ||
635 | adapter->currentpacketfilter &= | ||
636 | ~cmd_act_mac_promiscuous_enable; | ||
637 | |||
638 | if (dev->flags & IFF_ALLMULTI || dev->mc_count > | ||
639 | MRVDRV_MAX_MULTICAST_LIST_SIZE) { | ||
640 | lbs_pr_debug(1, "Enabling All Multicast!\n"); | ||
641 | adapter->currentpacketfilter |= | ||
642 | cmd_act_mac_all_multicast_enable; | ||
643 | adapter->currentpacketfilter &= | ||
644 | ~cmd_act_mac_multicast_enable; | ||
645 | } else { | ||
646 | adapter->currentpacketfilter &= | ||
647 | ~cmd_act_mac_all_multicast_enable; | ||
648 | |||
649 | if (!dev->mc_count) { | ||
650 | lbs_pr_debug(1, "No multicast addresses - " | ||
651 | "disabling multicast!\n"); | ||
652 | adapter->currentpacketfilter &= | ||
653 | ~cmd_act_mac_multicast_enable; | ||
654 | } else { | ||
655 | int i; | ||
656 | |||
657 | adapter->currentpacketfilter |= | ||
658 | cmd_act_mac_multicast_enable; | ||
659 | |||
660 | adapter->nr_of_multicastmacaddr = | ||
661 | wlan_copy_multicast_address(adapter, dev); | ||
662 | |||
663 | lbs_pr_debug(1, "Multicast addresses: %d\n", | ||
664 | dev->mc_count); | ||
665 | |||
666 | for (i = 0; i < dev->mc_count; i++) { | ||
667 | lbs_pr_debug(1, "Multicast address %d:" | ||
668 | "%x %x %x %x %x %x\n", i, | ||
669 | adapter->multicastlist[i][0], | ||
670 | adapter->multicastlist[i][1], | ||
671 | adapter->multicastlist[i][2], | ||
672 | adapter->multicastlist[i][3], | ||
673 | adapter->multicastlist[i][4], | ||
674 | adapter->multicastlist[i][5]); | ||
675 | } | ||
676 | /* set multicast addresses to firmware */ | ||
677 | libertas_prepare_and_send_command(priv, | ||
678 | cmd_mac_multicast_adr, | ||
679 | cmd_act_set, 0, 0, | ||
680 | NULL); | ||
681 | } | ||
682 | } | ||
683 | } | ||
684 | |||
685 | if (adapter->currentpacketfilter != oldpacketfilter) { | ||
686 | libertas_set_mac_packet_filter(priv); | ||
687 | } | ||
688 | |||
689 | LEAVE(); | ||
690 | } | ||
691 | |||
692 | /** | ||
693 | * @brief This function hanldes the major job in WLAN driver. | ||
694 | * it handles the event generated by firmware, rx data received | ||
695 | * from firmware and tx data sent from kernel. | ||
696 | * | ||
697 | * @param data A pointer to wlan_thread structure | ||
698 | * @return 0 | ||
699 | */ | ||
700 | static int wlan_service_main_thread(void *data) | ||
701 | { | ||
702 | struct wlan_thread *thread = data; | ||
703 | wlan_private *priv = thread->priv; | ||
704 | wlan_adapter *adapter = priv->adapter; | ||
705 | wait_queue_t wait; | ||
706 | u8 ireg = 0; | ||
707 | |||
708 | ENTER(); | ||
709 | |||
710 | wlan_activate_thread(thread); | ||
711 | |||
712 | init_waitqueue_entry(&wait, current); | ||
713 | |||
714 | for (;;) { | ||
715 | lbs_pr_debug(1, "main-thread 111: intcounter=%d " | ||
716 | "currenttxskb=%p dnld_sent=%d\n", | ||
717 | adapter->intcounter, | ||
718 | adapter->currenttxskb, priv->wlan_dev.dnld_sent); | ||
719 | |||
720 | add_wait_queue(&thread->waitq, &wait); | ||
721 | set_current_state(TASK_INTERRUPTIBLE); | ||
722 | spin_lock_irq(&adapter->driver_lock); | ||
723 | if ((adapter->psstate == PS_STATE_SLEEP) || | ||
724 | (!adapter->intcounter | ||
725 | && (priv->wlan_dev.dnld_sent || adapter->cur_cmd || | ||
726 | list_empty(&adapter->cmdpendingq)))) { | ||
727 | lbs_pr_debug(1, | ||
728 | "main-thread sleeping... Conn=%d IntC=%d PS_mode=%d PS_State=%d\n", | ||
729 | adapter->connect_status, adapter->intcounter, | ||
730 | adapter->psmode, adapter->psstate); | ||
731 | spin_unlock_irq(&adapter->driver_lock); | ||
732 | schedule(); | ||
733 | } else | ||
734 | spin_unlock_irq(&adapter->driver_lock); | ||
735 | |||
736 | |||
737 | lbs_pr_debug(1, | ||
738 | "main-thread 222 (waking up): intcounter=%d currenttxskb=%p " | ||
739 | "dnld_sent=%d\n", adapter->intcounter, | ||
740 | adapter->currenttxskb, priv->wlan_dev.dnld_sent); | ||
741 | |||
742 | set_current_state(TASK_RUNNING); | ||
743 | remove_wait_queue(&thread->waitq, &wait); | ||
744 | try_to_freeze(); | ||
745 | |||
746 | lbs_pr_debug(1, "main-thread 333: intcounter=%d currenttxskb=%p " | ||
747 | "dnld_sent=%d\n", | ||
748 | adapter->intcounter, | ||
749 | adapter->currenttxskb, priv->wlan_dev.dnld_sent); | ||
750 | |||
751 | if (kthread_should_stop() | ||
752 | || adapter->surpriseremoved) { | ||
753 | lbs_pr_debug(1, | ||
754 | "main-thread: break from main thread: surpriseremoved=0x%x\n", | ||
755 | adapter->surpriseremoved); | ||
756 | break; | ||
757 | } | ||
758 | |||
759 | |||
760 | spin_lock_irq(&adapter->driver_lock); | ||
761 | if (adapter->intcounter) { | ||
762 | u8 int_status; | ||
763 | adapter->intcounter = 0; | ||
764 | int_status = libertas_sbi_get_int_status(priv, &ireg); | ||
765 | |||
766 | if (int_status) { | ||
767 | lbs_pr_debug(1, | ||
768 | "main-thread: reading HOST_INT_STATUS_REG failed\n"); | ||
769 | spin_unlock_irq(&adapter->driver_lock); | ||
770 | continue; | ||
771 | } | ||
772 | adapter->hisregcpy |= ireg; | ||
773 | } | ||
774 | |||
775 | lbs_pr_debug(1, "main-thread 444: intcounter=%d currenttxskb=%p " | ||
776 | "dnld_sent=%d\n", | ||
777 | adapter->intcounter, | ||
778 | adapter->currenttxskb, priv->wlan_dev.dnld_sent); | ||
779 | |||
780 | /* command response? */ | ||
781 | if (adapter->hisregcpy & his_cmdupldrdy) { | ||
782 | lbs_pr_debug(1, "main-thread: cmd response ready.\n"); | ||
783 | |||
784 | adapter->hisregcpy &= ~his_cmdupldrdy; | ||
785 | spin_unlock_irq(&adapter->driver_lock); | ||
786 | libertas_process_rx_command(priv); | ||
787 | spin_lock_irq(&adapter->driver_lock); | ||
788 | } | ||
789 | |||
790 | /* Any Card Event */ | ||
791 | if (adapter->hisregcpy & his_cardevent) { | ||
792 | lbs_pr_debug(1, "main-thread: Card Event Activity.\n"); | ||
793 | |||
794 | adapter->hisregcpy &= ~his_cardevent; | ||
795 | |||
796 | if (libertas_sbi_read_event_cause(priv)) { | ||
797 | lbs_pr_alert( | ||
798 | "main-thread: libertas_sbi_read_event_cause failed.\n"); | ||
799 | spin_unlock_irq(&adapter->driver_lock); | ||
800 | continue; | ||
801 | } | ||
802 | spin_unlock_irq(&adapter->driver_lock); | ||
803 | libertas_process_event(priv); | ||
804 | } else | ||
805 | spin_unlock_irq(&adapter->driver_lock); | ||
806 | |||
807 | /* Check if we need to confirm Sleep Request received previously */ | ||
808 | if (adapter->psstate == PS_STATE_PRE_SLEEP) { | ||
809 | if (!priv->wlan_dev.dnld_sent && !adapter->cur_cmd) { | ||
810 | if (adapter->connect_status == | ||
811 | libertas_connected) { | ||
812 | lbs_pr_debug(1, | ||
813 | "main_thread: PRE_SLEEP--intcounter=%d currenttxskb=%p " | ||
814 | "dnld_sent=%d cur_cmd=%p, confirm now\n", | ||
815 | adapter->intcounter, | ||
816 | adapter->currenttxskb, | ||
817 | priv->wlan_dev.dnld_sent, | ||
818 | adapter->cur_cmd); | ||
819 | |||
820 | libertas_ps_confirm_sleep(priv, | ||
821 | (u16) adapter->psmode); | ||
822 | } else { | ||
823 | /* workaround for firmware sending | ||
824 | * deauth/linkloss event immediately | ||
825 | * after sleep request, remove this | ||
826 | * after firmware fixes it | ||
827 | */ | ||
828 | adapter->psstate = PS_STATE_AWAKE; | ||
829 | lbs_pr_alert( | ||
830 | "main-thread: ignore PS_SleepConfirm in non-connected state\n"); | ||
831 | } | ||
832 | } | ||
833 | } | ||
834 | |||
835 | /* The PS state is changed during processing of Sleep Request | ||
836 | * event above | ||
837 | */ | ||
838 | if ((priv->adapter->psstate == PS_STATE_SLEEP) || | ||
839 | (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) | ||
840 | continue; | ||
841 | |||
842 | /* Execute the next command */ | ||
843 | if (!priv->wlan_dev.dnld_sent && !priv->adapter->cur_cmd) | ||
844 | libertas_execute_next_command(priv); | ||
845 | |||
846 | /* Wake-up command waiters which can't sleep in | ||
847 | * libertas_prepare_and_send_command | ||
848 | */ | ||
849 | if (!adapter->nr_cmd_pending) | ||
850 | wake_up_all(&adapter->cmd_pending); | ||
851 | |||
852 | libertas_tx_runqueue(priv); | ||
853 | } | ||
854 | |||
855 | del_timer(&adapter->command_timer); | ||
856 | adapter->nr_cmd_pending = 0; | ||
857 | wake_up_all(&adapter->cmd_pending); | ||
858 | wlan_deactivate_thread(thread); | ||
859 | |||
860 | LEAVE(); | ||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | /** | ||
865 | * @brief This function adds the card. it will probe the | ||
866 | * card, allocate the wlan_priv and initialize the device. | ||
867 | * | ||
868 | * @param card A pointer to card | ||
869 | * @return A pointer to wlan_private structure | ||
870 | */ | ||
871 | wlan_private *wlan_add_card(void *card) | ||
872 | { | ||
873 | struct net_device *dev = NULL; | ||
874 | struct net_device *mesh_dev = NULL; | ||
875 | wlan_private *priv = NULL; | ||
876 | |||
877 | ENTER(); | ||
878 | |||
879 | /* Allocate an Ethernet device and register it */ | ||
880 | if (!(dev = alloc_etherdev(sizeof(wlan_private)))) { | ||
881 | lbs_pr_alert( "Init ethernet device failed!\n"); | ||
882 | return NULL; | ||
883 | } | ||
884 | |||
885 | priv = dev->priv; | ||
886 | |||
887 | /* allocate buffer for wlan_adapter */ | ||
888 | if (!(priv->adapter = kmalloc(sizeof(wlan_adapter), GFP_KERNEL))) { | ||
889 | lbs_pr_alert( "Allocate buffer for wlan_adapter failed!\n"); | ||
890 | goto err_kmalloc; | ||
891 | } | ||
892 | |||
893 | /* Allocate a virtual mesh device */ | ||
894 | if (!(mesh_dev = alloc_netdev(0, "msh%d", ether_setup))) { | ||
895 | lbs_pr_debug(1, "Init ethernet device failed!\n"); | ||
896 | return NULL; | ||
897 | } | ||
898 | |||
899 | /* Both intervaces share the priv structure */ | ||
900 | mesh_dev->priv = priv; | ||
901 | |||
902 | /* init wlan_adapter */ | ||
903 | memset(priv->adapter, 0, sizeof(wlan_adapter)); | ||
904 | |||
905 | priv->wlan_dev.netdev = dev; | ||
906 | priv->wlan_dev.card = card; | ||
907 | priv->mesh_open = 0; | ||
908 | priv->infra_open = 0; | ||
909 | priv->mesh_dev = mesh_dev; | ||
910 | wlanpriv = priv; | ||
911 | |||
912 | SET_MODULE_OWNER(dev); | ||
913 | SET_MODULE_OWNER(mesh_dev); | ||
914 | |||
915 | /* Setup the OS Interface to our functions */ | ||
916 | dev->open = wlan_open; | ||
917 | dev->hard_start_xmit = wlan_pre_start_xmit; | ||
918 | dev->stop = wlan_close; | ||
919 | dev->do_ioctl = libertas_do_ioctl; | ||
920 | dev->set_mac_address = wlan_set_mac_address; | ||
921 | mesh_dev->open = mesh_open; | ||
922 | mesh_dev->hard_start_xmit = mesh_pre_start_xmit; | ||
923 | mesh_dev->stop = mesh_close; | ||
924 | mesh_dev->do_ioctl = libertas_do_ioctl; | ||
925 | memcpy(mesh_dev->dev_addr, wlanpriv->wlan_dev.netdev->dev_addr, | ||
926 | sizeof(wlanpriv->wlan_dev.netdev->dev_addr)); | ||
927 | |||
928 | #define WLAN_WATCHDOG_TIMEOUT (5 * HZ) | ||
929 | |||
930 | dev->tx_timeout = wlan_tx_timeout; | ||
931 | dev->get_stats = wlan_get_stats; | ||
932 | dev->watchdog_timeo = WLAN_WATCHDOG_TIMEOUT; | ||
933 | dev->ethtool_ops = &libertas_ethtool_ops; | ||
934 | mesh_dev->get_stats = wlan_get_stats; | ||
935 | mesh_dev->ethtool_ops = &libertas_ethtool_ops; | ||
936 | |||
937 | #ifdef WIRELESS_EXT | ||
938 | dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def; | ||
939 | mesh_dev->wireless_handlers = (struct iw_handler_def *)&libertas_handler_def; | ||
940 | #endif | ||
941 | #define NETIF_F_DYNALLOC 16 | ||
942 | dev->features |= NETIF_F_DYNALLOC; | ||
943 | dev->flags |= IFF_BROADCAST | IFF_MULTICAST; | ||
944 | dev->set_multicast_list = wlan_set_multicast_list; | ||
945 | |||
946 | INIT_LIST_HEAD(&priv->adapter->cmdfreeq); | ||
947 | INIT_LIST_HEAD(&priv->adapter->cmdpendingq); | ||
948 | |||
949 | spin_lock_init(&priv->adapter->driver_lock); | ||
950 | init_waitqueue_head(&priv->adapter->cmd_pending); | ||
951 | priv->adapter->nr_cmd_pending = 0; | ||
952 | |||
953 | lbs_pr_debug(1, "Starting kthread...\n"); | ||
954 | priv->mainthread.priv = priv; | ||
955 | wlan_create_thread(wlan_service_main_thread, | ||
956 | &priv->mainthread, "wlan_main_service"); | ||
957 | |||
958 | priv->assoc_thread = | ||
959 | create_singlethread_workqueue("libertas_assoc"); | ||
960 | INIT_DELAYED_WORK(&priv->assoc_work, wlan_association_worker); | ||
961 | |||
962 | /* | ||
963 | * Register the device. Fillup the private data structure with | ||
964 | * relevant information from the card and request for the required | ||
965 | * IRQ. | ||
966 | */ | ||
967 | if (libertas_sbi_register_dev(priv) < 0) { | ||
968 | lbs_pr_info("failed to register wlan device!\n"); | ||
969 | goto err_registerdev; | ||
970 | } | ||
971 | |||
972 | /* init FW and HW */ | ||
973 | if (libertas_init_fw(priv)) { | ||
974 | lbs_pr_debug(1, "Firmware Init failed\n"); | ||
975 | goto err_registerdev; | ||
976 | } | ||
977 | |||
978 | if (register_netdev(dev)) { | ||
979 | lbs_pr_err("Cannot register network device!\n"); | ||
980 | goto err_init_fw; | ||
981 | } | ||
982 | |||
983 | /* Register virtual mesh interface */ | ||
984 | if (register_netdev(mesh_dev)) { | ||
985 | lbs_pr_info("Cannot register mesh virtual interface!\n"); | ||
986 | goto err_init_fw; | ||
987 | } | ||
988 | |||
989 | lbs_pr_info("%s: Marvell Wlan 802.11 adapter ", dev->name); | ||
990 | |||
991 | libertas_debugfs_init_one(priv, dev); | ||
992 | |||
993 | if (libertas_found == MAX_DEVS) | ||
994 | goto err_init_fw; | ||
995 | libertas_devs[libertas_found] = dev; | ||
996 | libertas_found++; | ||
997 | #ifdef ENABLE_PM | ||
998 | if (!(wlan_pm_dev = pm_register(PM_UNKNOWN_DEV, 0, wlan_pm_callback))) | ||
999 | lbs_pr_alert( "failed to register PM callback\n"); | ||
1000 | #endif | ||
1001 | if (device_create_file(&(mesh_dev->dev), &dev_attr_libertas_mpp)) | ||
1002 | goto err_create_file; | ||
1003 | |||
1004 | LEAVE(); | ||
1005 | return priv; | ||
1006 | |||
1007 | err_create_file: | ||
1008 | device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp); | ||
1009 | err_init_fw: | ||
1010 | libertas_sbi_unregister_dev(priv); | ||
1011 | err_registerdev: | ||
1012 | destroy_workqueue(priv->assoc_thread); | ||
1013 | /* Stop the thread servicing the interrupts */ | ||
1014 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1015 | wlan_terminate_thread(&priv->mainthread); | ||
1016 | kfree(priv->adapter); | ||
1017 | err_kmalloc: | ||
1018 | free_netdev(dev); | ||
1019 | free_netdev(mesh_dev); | ||
1020 | wlanpriv = NULL; | ||
1021 | |||
1022 | LEAVE(); | ||
1023 | return NULL; | ||
1024 | } | ||
1025 | |||
1026 | static void wake_pending_cmdnodes(wlan_private *priv) | ||
1027 | { | ||
1028 | struct cmd_ctrl_node *cmdnode; | ||
1029 | unsigned long flags; | ||
1030 | |||
1031 | spin_lock_irqsave(&priv->adapter->driver_lock, flags); | ||
1032 | list_for_each_entry(cmdnode, &priv->adapter->cmdpendingq, list) { | ||
1033 | cmdnode->cmdwaitqwoken = 1; | ||
1034 | wake_up_interruptible(&cmdnode->cmdwait_q); | ||
1035 | } | ||
1036 | spin_unlock_irqrestore(&priv->adapter->driver_lock, flags); | ||
1037 | } | ||
1038 | |||
1039 | |||
1040 | int wlan_remove_card(void *card) | ||
1041 | { | ||
1042 | wlan_private *priv = libertas_sbi_get_priv(card); | ||
1043 | wlan_adapter *adapter; | ||
1044 | struct net_device *dev; | ||
1045 | struct net_device *mesh_dev; | ||
1046 | union iwreq_data wrqu; | ||
1047 | int i; | ||
1048 | |||
1049 | ENTER(); | ||
1050 | |||
1051 | if (!priv) { | ||
1052 | LEAVE(); | ||
1053 | return 0; | ||
1054 | } | ||
1055 | |||
1056 | adapter = priv->adapter; | ||
1057 | |||
1058 | if (!adapter) { | ||
1059 | LEAVE(); | ||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | dev = priv->wlan_dev.netdev; | ||
1064 | mesh_dev = priv->mesh_dev; | ||
1065 | |||
1066 | netif_stop_queue(mesh_dev); | ||
1067 | netif_stop_queue(priv->wlan_dev.netdev); | ||
1068 | netif_carrier_off(priv->wlan_dev.netdev); | ||
1069 | |||
1070 | wake_pending_cmdnodes(priv); | ||
1071 | |||
1072 | device_remove_file(&(mesh_dev->dev), &dev_attr_libertas_mpp); | ||
1073 | unregister_netdev(mesh_dev); | ||
1074 | unregister_netdev(dev); | ||
1075 | |||
1076 | cancel_delayed_work(&priv->assoc_work); | ||
1077 | destroy_workqueue(priv->assoc_thread); | ||
1078 | |||
1079 | if (adapter->psmode == wlan802_11powermodemax_psp) { | ||
1080 | adapter->psmode = wlan802_11powermodecam; | ||
1081 | libertas_ps_wakeup(priv, cmd_option_waitforrsp); | ||
1082 | } | ||
1083 | |||
1084 | memset(wrqu.ap_addr.sa_data, 0xaa, ETH_ALEN); | ||
1085 | wrqu.ap_addr.sa_family = ARPHRD_ETHER; | ||
1086 | wireless_send_event(priv->wlan_dev.netdev, SIOCGIWAP, &wrqu, NULL); | ||
1087 | |||
1088 | #ifdef ENABLE_PM | ||
1089 | pm_unregister(wlan_pm_dev); | ||
1090 | #endif | ||
1091 | |||
1092 | adapter->surpriseremoved = 1; | ||
1093 | |||
1094 | /* Stop the thread servicing the interrupts */ | ||
1095 | wlan_terminate_thread(&priv->mainthread); | ||
1096 | |||
1097 | libertas_debugfs_remove_one(priv); | ||
1098 | |||
1099 | lbs_pr_debug(1, "Free adapter\n"); | ||
1100 | libertas_free_adapter(priv); | ||
1101 | |||
1102 | for (i = 0; i<libertas_found; i++) { | ||
1103 | if (libertas_devs[i]==priv->wlan_dev.netdev) { | ||
1104 | libertas_devs[i] = libertas_devs[--libertas_found]; | ||
1105 | libertas_devs[libertas_found] = NULL ; | ||
1106 | break ; | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | lbs_pr_debug(1, "Unregister finish\n"); | ||
1111 | |||
1112 | priv->wlan_dev.netdev = NULL; | ||
1113 | priv->mesh_dev = NULL ; | ||
1114 | free_netdev(mesh_dev); | ||
1115 | free_netdev(dev); | ||
1116 | wlanpriv = NULL; | ||
1117 | |||
1118 | LEAVE(); | ||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
1122 | /** | ||
1123 | * @brief This function finds the CFP in | ||
1124 | * region_cfp_table based on region and band parameter. | ||
1125 | * | ||
1126 | * @param region The region code | ||
1127 | * @param band The band | ||
1128 | * @param cfp_no A pointer to CFP number | ||
1129 | * @return A pointer to CFP | ||
1130 | */ | ||
1131 | struct chan_freq_power *libertas_get_region_cfp_table(u8 region, u8 band, int *cfp_no) | ||
1132 | { | ||
1133 | int i, end; | ||
1134 | |||
1135 | ENTER(); | ||
1136 | |||
1137 | end = sizeof(region_cfp_table)/sizeof(struct region_cfp_table); | ||
1138 | |||
1139 | for (i = 0; i < end ; i++) { | ||
1140 | lbs_pr_debug(1, "region_cfp_table[i].region=%d\n", | ||
1141 | region_cfp_table[i].region); | ||
1142 | if (region_cfp_table[i].region == region) { | ||
1143 | *cfp_no = region_cfp_table[i].cfp_no_BG; | ||
1144 | LEAVE(); | ||
1145 | return region_cfp_table[i].cfp_BG; | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | LEAVE(); | ||
1150 | return NULL; | ||
1151 | } | ||
1152 | |||
1153 | int libertas_set_regiontable(wlan_private * priv, u8 region, u8 band) | ||
1154 | { | ||
1155 | wlan_adapter *adapter = priv->adapter; | ||
1156 | int i = 0; | ||
1157 | |||
1158 | struct chan_freq_power *cfp; | ||
1159 | int cfp_no; | ||
1160 | |||
1161 | ENTER(); | ||
1162 | |||
1163 | memset(adapter->region_channel, 0, sizeof(adapter->region_channel)); | ||
1164 | |||
1165 | { | ||
1166 | cfp = libertas_get_region_cfp_table(region, band, &cfp_no); | ||
1167 | if (cfp != NULL) { | ||
1168 | adapter->region_channel[i].nrcfp = cfp_no; | ||
1169 | adapter->region_channel[i].CFP = cfp; | ||
1170 | } else { | ||
1171 | lbs_pr_debug(1, "wrong region code %#x in band B-G\n", | ||
1172 | region); | ||
1173 | return -1; | ||
1174 | } | ||
1175 | adapter->region_channel[i].valid = 1; | ||
1176 | adapter->region_channel[i].region = region; | ||
1177 | adapter->region_channel[i].band = band; | ||
1178 | i++; | ||
1179 | } | ||
1180 | LEAVE(); | ||
1181 | return 0; | ||
1182 | } | ||
1183 | |||
1184 | /** | ||
1185 | * @brief This function handles the interrupt. it will change PS | ||
1186 | * state if applicable. it will wake up main_thread to handle | ||
1187 | * the interrupt event as well. | ||
1188 | * | ||
1189 | * @param dev A pointer to net_device structure | ||
1190 | * @return n/a | ||
1191 | */ | ||
1192 | void libertas_interrupt(struct net_device *dev) | ||
1193 | { | ||
1194 | wlan_private *priv = dev->priv; | ||
1195 | |||
1196 | ENTER(); | ||
1197 | |||
1198 | lbs_pr_debug(1, "libertas_interrupt: intcounter=%d\n", | ||
1199 | priv->adapter->intcounter); | ||
1200 | |||
1201 | priv->adapter->intcounter++; | ||
1202 | |||
1203 | if (priv->adapter->psstate == PS_STATE_SLEEP) { | ||
1204 | priv->adapter->psstate = PS_STATE_AWAKE; | ||
1205 | netif_wake_queue(dev); | ||
1206 | } | ||
1207 | |||
1208 | wake_up_interruptible(&priv->mainthread.waitq); | ||
1209 | |||
1210 | LEAVE(); | ||
1211 | } | ||
1212 | |||
1213 | static int wlan_init_module(void) | ||
1214 | { | ||
1215 | int ret = 0; | ||
1216 | |||
1217 | ENTER(); | ||
1218 | |||
1219 | if (libertas_fw_name == NULL) { | ||
1220 | libertas_fw_name = default_fw_name; | ||
1221 | } | ||
1222 | |||
1223 | libertas_debugfs_init(); | ||
1224 | |||
1225 | if (libertas_sbi_register()) { | ||
1226 | ret = -1; | ||
1227 | libertas_debugfs_remove(); | ||
1228 | goto done; | ||
1229 | } | ||
1230 | |||
1231 | done: | ||
1232 | LEAVE(); | ||
1233 | return ret; | ||
1234 | } | ||
1235 | |||
1236 | static void wlan_cleanup_module(void) | ||
1237 | { | ||
1238 | int i; | ||
1239 | |||
1240 | ENTER(); | ||
1241 | |||
1242 | for (i = 0; i<libertas_found; i++) { | ||
1243 | wlan_private *priv = libertas_devs[i]->priv; | ||
1244 | reset_device(priv); | ||
1245 | } | ||
1246 | |||
1247 | libertas_sbi_unregister(); | ||
1248 | libertas_debugfs_remove(); | ||
1249 | |||
1250 | LEAVE(); | ||
1251 | } | ||
1252 | |||
1253 | module_init(wlan_init_module); | ||
1254 | module_exit(wlan_cleanup_module); | ||
1255 | |||
1256 | MODULE_DESCRIPTION("M-WLAN Driver"); | ||
1257 | MODULE_AUTHOR("Marvell International Ltd."); | ||
1258 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h new file mode 100644 index 000000000000..5d118f40cfbc --- /dev/null +++ b/drivers/net/wireless/libertas/radiotap.h | |||
@@ -0,0 +1,57 @@ | |||
1 | #include <net/ieee80211_radiotap.h> | ||
2 | |||
3 | struct tx_radiotap_hdr { | ||
4 | struct ieee80211_radiotap_header hdr; | ||
5 | u8 rate; | ||
6 | u8 txpower; | ||
7 | u8 rts_retries; | ||
8 | u8 data_retries; | ||
9 | #if 0 | ||
10 | u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12]; | ||
11 | #endif | ||
12 | } __attribute__ ((packed)); | ||
13 | |||
14 | #define TX_RADIOTAP_PRESENT ( \ | ||
15 | (1 << IEEE80211_RADIOTAP_RATE) | \ | ||
16 | (1 << IEEE80211_RADIOTAP_DBM_TX_POWER) | \ | ||
17 | (1 << IEEE80211_RADIOTAP_RTS_RETRIES) | \ | ||
18 | (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | \ | ||
19 | 0) | ||
20 | |||
21 | #define IEEE80211_FC_VERSION_MASK 0x0003 | ||
22 | #define IEEE80211_FC_TYPE_MASK 0x000c | ||
23 | #define IEEE80211_FC_TYPE_MGT 0x0000 | ||
24 | #define IEEE80211_FC_TYPE_CTL 0x0004 | ||
25 | #define IEEE80211_FC_TYPE_DATA 0x0008 | ||
26 | #define IEEE80211_FC_SUBTYPE_MASK 0x00f0 | ||
27 | #define IEEE80211_FC_TOFROMDS_MASK 0x0300 | ||
28 | #define IEEE80211_FC_TODS_MASK 0x0100 | ||
29 | #define IEEE80211_FC_FROMDS_MASK 0x0200 | ||
30 | #define IEEE80211_FC_NODS 0x0000 | ||
31 | #define IEEE80211_FC_TODS 0x0100 | ||
32 | #define IEEE80211_FC_FROMDS 0x0200 | ||
33 | #define IEEE80211_FC_DSTODS 0x0300 | ||
34 | |||
35 | struct rx_radiotap_hdr { | ||
36 | struct ieee80211_radiotap_header hdr; | ||
37 | u8 flags; | ||
38 | u8 rate; | ||
39 | u16 chan_freq; | ||
40 | u16 chan_flags; | ||
41 | u8 antenna; | ||
42 | u8 antsignal; | ||
43 | u16 rx_flags; | ||
44 | #if 0 | ||
45 | u8 pad[IEEE80211_RADIOTAP_HDRLEN - 18]; | ||
46 | #endif | ||
47 | } __attribute__ ((packed)); | ||
48 | |||
49 | #define RX_RADIOTAP_PRESENT ( \ | ||
50 | (1 << IEEE80211_RADIOTAP_FLAGS) | \ | ||
51 | (1 << IEEE80211_RADIOTAP_RATE) | \ | ||
52 | (1 << IEEE80211_RADIOTAP_CHANNEL) | \ | ||
53 | (1 << IEEE80211_RADIOTAP_ANTENNA) | \ | ||
54 | (1 << IEEE80211_RADIOTAP_DB_ANTSIGNAL) |\ | ||
55 | (1 << IEEE80211_RADIOTAP_RX_FLAGS) | \ | ||
56 | 0) | ||
57 | |||
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c new file mode 100644 index 000000000000..7e3f78f092dc --- /dev/null +++ b/drivers/net/wireless/libertas/rx.c | |||
@@ -0,0 +1,459 @@ | |||
1 | /** | ||
2 | * This file contains the handling of RX in wlan driver. | ||
3 | */ | ||
4 | #include <linux/etherdevice.h> | ||
5 | #include <linux/types.h> | ||
6 | |||
7 | #include "hostcmd.h" | ||
8 | #include "radiotap.h" | ||
9 | #include "decl.h" | ||
10 | #include "dev.h" | ||
11 | #include "wext.h" | ||
12 | |||
13 | struct eth803hdr { | ||
14 | u8 dest_addr[6]; | ||
15 | u8 src_addr[6]; | ||
16 | u16 h803_len; | ||
17 | } __attribute__ ((packed)); | ||
18 | |||
19 | struct rfc1042hdr { | ||
20 | u8 llc_dsap; | ||
21 | u8 llc_ssap; | ||
22 | u8 llc_ctrl; | ||
23 | u8 snap_oui[3]; | ||
24 | u16 snap_type; | ||
25 | } __attribute__ ((packed)); | ||
26 | |||
27 | struct rxpackethdr { | ||
28 | struct rxpd rx_pd; | ||
29 | struct eth803hdr eth803_hdr; | ||
30 | struct rfc1042hdr rfc1042_hdr; | ||
31 | } __attribute__ ((packed)); | ||
32 | |||
33 | struct rx80211packethdr { | ||
34 | struct rxpd rx_pd; | ||
35 | void *eth80211_hdr; | ||
36 | } __attribute__ ((packed)); | ||
37 | |||
38 | static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb); | ||
39 | |||
40 | /** | ||
41 | * @brief This function computes the avgSNR . | ||
42 | * | ||
43 | * @param priv A pointer to wlan_private structure | ||
44 | * @return avgSNR | ||
45 | */ | ||
46 | static u8 wlan_getavgsnr(wlan_private * priv) | ||
47 | { | ||
48 | u8 i; | ||
49 | u16 temp = 0; | ||
50 | wlan_adapter *adapter = priv->adapter; | ||
51 | if (adapter->numSNRNF == 0) | ||
52 | return 0; | ||
53 | for (i = 0; i < adapter->numSNRNF; i++) | ||
54 | temp += adapter->rawSNR[i]; | ||
55 | return (u8) (temp / adapter->numSNRNF); | ||
56 | |||
57 | } | ||
58 | |||
59 | /** | ||
60 | * @brief This function computes the AvgNF | ||
61 | * | ||
62 | * @param priv A pointer to wlan_private structure | ||
63 | * @return AvgNF | ||
64 | */ | ||
65 | static u8 wlan_getavgnf(wlan_private * priv) | ||
66 | { | ||
67 | u8 i; | ||
68 | u16 temp = 0; | ||
69 | wlan_adapter *adapter = priv->adapter; | ||
70 | if (adapter->numSNRNF == 0) | ||
71 | return 0; | ||
72 | for (i = 0; i < adapter->numSNRNF; i++) | ||
73 | temp += adapter->rawNF[i]; | ||
74 | return (u8) (temp / adapter->numSNRNF); | ||
75 | |||
76 | } | ||
77 | |||
78 | /** | ||
79 | * @brief This function save the raw SNR/NF to our internel buffer | ||
80 | * | ||
81 | * @param priv A pointer to wlan_private structure | ||
82 | * @param prxpd A pointer to rxpd structure of received packet | ||
83 | * @return n/a | ||
84 | */ | ||
85 | static void wlan_save_rawSNRNF(wlan_private * priv, struct rxpd *p_rx_pd) | ||
86 | { | ||
87 | wlan_adapter *adapter = priv->adapter; | ||
88 | if (adapter->numSNRNF < adapter->data_avg_factor) | ||
89 | adapter->numSNRNF++; | ||
90 | adapter->rawSNR[adapter->nextSNRNF] = p_rx_pd->snr; | ||
91 | adapter->rawNF[adapter->nextSNRNF] = p_rx_pd->nf; | ||
92 | adapter->nextSNRNF++; | ||
93 | if (adapter->nextSNRNF >= adapter->data_avg_factor) | ||
94 | adapter->nextSNRNF = 0; | ||
95 | return; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * @brief This function computes the RSSI in received packet. | ||
100 | * | ||
101 | * @param priv A pointer to wlan_private structure | ||
102 | * @param prxpd A pointer to rxpd structure of received packet | ||
103 | * @return n/a | ||
104 | */ | ||
105 | static void wlan_compute_rssi(wlan_private * priv, struct rxpd *p_rx_pd) | ||
106 | { | ||
107 | wlan_adapter *adapter = priv->adapter; | ||
108 | |||
109 | ENTER(); | ||
110 | |||
111 | lbs_pr_debug(1, "rxpd: SNR = %d, NF = %d\n", p_rx_pd->snr, p_rx_pd->nf); | ||
112 | lbs_pr_debug(1, "Before computing SNR: SNR- avg = %d, NF-avg = %d\n", | ||
113 | adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, | ||
114 | adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); | ||
115 | |||
116 | adapter->SNR[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->snr; | ||
117 | adapter->NF[TYPE_RXPD][TYPE_NOAVG] = p_rx_pd->nf; | ||
118 | wlan_save_rawSNRNF(priv, p_rx_pd); | ||
119 | |||
120 | adapter->rxpd_rate = p_rx_pd->rx_rate; | ||
121 | |||
122 | adapter->SNR[TYPE_RXPD][TYPE_AVG] = wlan_getavgsnr(priv) * AVG_SCALE; | ||
123 | adapter->NF[TYPE_RXPD][TYPE_AVG] = wlan_getavgnf(priv) * AVG_SCALE; | ||
124 | lbs_pr_debug(1, "After computing SNR: SNR-avg = %d, NF-avg = %d\n", | ||
125 | adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, | ||
126 | adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); | ||
127 | |||
128 | adapter->RSSI[TYPE_RXPD][TYPE_NOAVG] = | ||
129 | CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], | ||
130 | adapter->NF[TYPE_RXPD][TYPE_NOAVG]); | ||
131 | |||
132 | adapter->RSSI[TYPE_RXPD][TYPE_AVG] = | ||
133 | CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, | ||
134 | adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); | ||
135 | |||
136 | LEAVE(); | ||
137 | } | ||
138 | |||
139 | int libertas_upload_rx_packet(wlan_private * priv, struct sk_buff *skb) | ||
140 | { | ||
141 | lbs_pr_debug(1, "skb->data=%p\n", skb->data); | ||
142 | |||
143 | if(IS_MESH_FRAME(skb)) | ||
144 | skb->dev = priv->mesh_dev; | ||
145 | else | ||
146 | skb->dev = priv->wlan_dev.netdev; | ||
147 | skb->protocol = eth_type_trans(skb, priv->wlan_dev.netdev); | ||
148 | skb->ip_summed = CHECKSUM_UNNECESSARY; | ||
149 | |||
150 | netif_rx(skb); | ||
151 | |||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | /** | ||
156 | * @brief This function processes received packet and forwards it | ||
157 | * to kernel/upper layer | ||
158 | * | ||
159 | * @param priv A pointer to wlan_private | ||
160 | * @param skb A pointer to skb which includes the received packet | ||
161 | * @return 0 or -1 | ||
162 | */ | ||
163 | int libertas_process_rxed_packet(wlan_private * priv, struct sk_buff *skb) | ||
164 | { | ||
165 | wlan_adapter *adapter = priv->adapter; | ||
166 | int ret = 0; | ||
167 | |||
168 | struct rxpackethdr *p_rx_pkt; | ||
169 | struct rxpd *p_rx_pd; | ||
170 | |||
171 | int hdrchop; | ||
172 | struct ethhdr *p_ethhdr; | ||
173 | |||
174 | const u8 rfc1042_eth_hdr[] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; | ||
175 | |||
176 | ENTER(); | ||
177 | |||
178 | if (priv->adapter->debugmode & MRVDRV_DEBUG_RX_PATH) | ||
179 | lbs_dbg_hex("RX packet: ", skb->data, | ||
180 | min_t(unsigned int, skb->len, 100)); | ||
181 | |||
182 | if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) | ||
183 | return process_rxed_802_11_packet(priv, skb); | ||
184 | |||
185 | p_rx_pkt = (struct rxpackethdr *) skb->data; | ||
186 | p_rx_pd = &p_rx_pkt->rx_pd; | ||
187 | if (p_rx_pd->rx_control & RxPD_MESH_FRAME) | ||
188 | SET_MESH_FRAME(skb); | ||
189 | else | ||
190 | UNSET_MESH_FRAME(skb); | ||
191 | |||
192 | lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, | ||
193 | min_t(unsigned int, skb->len, 100)); | ||
194 | |||
195 | if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { | ||
196 | lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n"); | ||
197 | priv->stats.rx_length_errors++; | ||
198 | ret = 0; | ||
199 | goto done; | ||
200 | } | ||
201 | |||
202 | /* | ||
203 | * Check rxpd status and update 802.3 stat, | ||
204 | */ | ||
205 | if (!(p_rx_pd->status & MRVDRV_RXPD_STATUS_OK)) { | ||
206 | lbs_pr_debug(1, "RX error: frame received with bad status\n"); | ||
207 | lbs_pr_alert("rxpd Not OK\n"); | ||
208 | priv->stats.rx_errors++; | ||
209 | ret = 0; | ||
210 | goto done; | ||
211 | } | ||
212 | |||
213 | lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n", | ||
214 | skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); | ||
215 | |||
216 | lbs_dbg_hex("RX Data: Dest", p_rx_pkt->eth803_hdr.dest_addr, | ||
217 | sizeof(p_rx_pkt->eth803_hdr.dest_addr)); | ||
218 | lbs_dbg_hex("RX Data: Src", p_rx_pkt->eth803_hdr.src_addr, | ||
219 | sizeof(p_rx_pkt->eth803_hdr.src_addr)); | ||
220 | |||
221 | if (memcmp(&p_rx_pkt->rfc1042_hdr, | ||
222 | rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) { | ||
223 | /* | ||
224 | * Replace the 803 header and rfc1042 header (llc/snap) with an | ||
225 | * EthernetII header, keep the src/dst and snap_type (ethertype) | ||
226 | * | ||
227 | * The firmware only passes up SNAP frames converting | ||
228 | * all RX Data from 802.11 to 802.2/LLC/SNAP frames. | ||
229 | * | ||
230 | * To create the Ethernet II, just move the src, dst address right | ||
231 | * before the snap_type. | ||
232 | */ | ||
233 | p_ethhdr = (struct ethhdr *) | ||
234 | ((u8 *) & p_rx_pkt->eth803_hdr | ||
235 | + sizeof(p_rx_pkt->eth803_hdr) + sizeof(p_rx_pkt->rfc1042_hdr) | ||
236 | - sizeof(p_rx_pkt->eth803_hdr.dest_addr) | ||
237 | - sizeof(p_rx_pkt->eth803_hdr.src_addr) | ||
238 | - sizeof(p_rx_pkt->rfc1042_hdr.snap_type)); | ||
239 | |||
240 | memcpy(p_ethhdr->h_source, p_rx_pkt->eth803_hdr.src_addr, | ||
241 | sizeof(p_ethhdr->h_source)); | ||
242 | memcpy(p_ethhdr->h_dest, p_rx_pkt->eth803_hdr.dest_addr, | ||
243 | sizeof(p_ethhdr->h_dest)); | ||
244 | |||
245 | /* Chop off the rxpd + the excess memory from the 802.2/llc/snap header | ||
246 | * that was removed | ||
247 | */ | ||
248 | hdrchop = (u8 *) p_ethhdr - (u8 *) p_rx_pkt; | ||
249 | } else { | ||
250 | lbs_dbg_hex("RX Data: LLC/SNAP", | ||
251 | (u8 *) & p_rx_pkt->rfc1042_hdr, | ||
252 | sizeof(p_rx_pkt->rfc1042_hdr)); | ||
253 | |||
254 | /* Chop off the rxpd */ | ||
255 | hdrchop = (u8 *) & p_rx_pkt->eth803_hdr - (u8 *) p_rx_pkt; | ||
256 | } | ||
257 | |||
258 | /* Chop off the leading header bytes so the skb points to the start of | ||
259 | * either the reconstructed EthII frame or the 802.2/llc/snap frame | ||
260 | */ | ||
261 | skb_pull(skb, hdrchop); | ||
262 | |||
263 | /* Take the data rate from the rxpd structure | ||
264 | * only if the rate is auto | ||
265 | */ | ||
266 | if (adapter->is_datarate_auto) | ||
267 | adapter->datarate = libertas_index_to_data_rate(p_rx_pd->rx_rate); | ||
268 | |||
269 | wlan_compute_rssi(priv, p_rx_pd); | ||
270 | |||
271 | lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len); | ||
272 | if (libertas_upload_rx_packet(priv, skb)) { | ||
273 | lbs_pr_debug(1, "RX error: libertas_upload_rx_packet" | ||
274 | " returns failure\n"); | ||
275 | ret = -1; | ||
276 | goto done; | ||
277 | } | ||
278 | priv->stats.rx_bytes += skb->len; | ||
279 | priv->stats.rx_packets++; | ||
280 | |||
281 | ret = 0; | ||
282 | done: | ||
283 | LEAVE(); | ||
284 | |||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | /** | ||
289 | * @brief This function converts Tx/Rx rates from the Marvell WLAN format | ||
290 | * (see Table 2 in Section 3.1) to IEEE80211_RADIOTAP_RATE units (500 Kb/s) | ||
291 | * | ||
292 | * @param rate Input rate | ||
293 | * @return Output Rate (0 if invalid) | ||
294 | */ | ||
295 | static u8 convert_mv_rate_to_radiotap(u8 rate) | ||
296 | { | ||
297 | switch (rate) { | ||
298 | case 0: /* 1 Mbps */ | ||
299 | return 2; | ||
300 | case 1: /* 2 Mbps */ | ||
301 | return 4; | ||
302 | case 2: /* 5.5 Mbps */ | ||
303 | return 11; | ||
304 | case 3: /* 11 Mbps */ | ||
305 | return 22; | ||
306 | case 4: /* 6 Mbps */ | ||
307 | return 12; | ||
308 | case 5: /* 9 Mbps */ | ||
309 | return 18; | ||
310 | case 6: /* 12 Mbps */ | ||
311 | return 24; | ||
312 | case 7: /* 18 Mbps */ | ||
313 | return 36; | ||
314 | case 8: /* 24 Mbps */ | ||
315 | return 48; | ||
316 | case 9: /* 36 Mbps */ | ||
317 | return 72; | ||
318 | case 10: /* 48 Mbps */ | ||
319 | return 96; | ||
320 | case 11: /* 54 Mbps */ | ||
321 | return 108; | ||
322 | } | ||
323 | lbs_pr_alert( "Invalid Marvell WLAN rate (%i)\n", rate); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | /** | ||
328 | * @brief This function processes a received 802.11 packet and forwards it | ||
329 | * to kernel/upper layer | ||
330 | * | ||
331 | * @param priv A pointer to wlan_private | ||
332 | * @param skb A pointer to skb which includes the received packet | ||
333 | * @return 0 or -1 | ||
334 | */ | ||
335 | static int process_rxed_802_11_packet(wlan_private * priv, struct sk_buff *skb) | ||
336 | { | ||
337 | wlan_adapter *adapter = priv->adapter; | ||
338 | int ret = 0; | ||
339 | |||
340 | struct rx80211packethdr *p_rx_pkt; | ||
341 | struct rxpd *prxpd; | ||
342 | struct rx_radiotap_hdr radiotap_hdr; | ||
343 | struct rx_radiotap_hdr *pradiotap_hdr; | ||
344 | |||
345 | ENTER(); | ||
346 | |||
347 | p_rx_pkt = (struct rx80211packethdr *) skb->data; | ||
348 | prxpd = &p_rx_pkt->rx_pd; | ||
349 | |||
350 | // lbs_dbg_hex("RX Data: Before chop rxpd", skb->data, min(skb->len, 100)); | ||
351 | |||
352 | if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) { | ||
353 | lbs_pr_debug(1, "RX error: FRAME RECEIVED WITH BAD LENGTH\n"); | ||
354 | priv->stats.rx_length_errors++; | ||
355 | ret = 0; | ||
356 | goto done; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * Check rxpd status and update 802.3 stat, | ||
361 | */ | ||
362 | if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) { | ||
363 | //lbs_pr_debug(1, "RX error: frame received with bad status\n"); | ||
364 | priv->stats.rx_errors++; | ||
365 | } | ||
366 | |||
367 | lbs_pr_debug(1, "RX Data: skb->len - sizeof(RxPd) = %d - %d = %d\n", | ||
368 | skb->len, sizeof(struct rxpd), skb->len - sizeof(struct rxpd)); | ||
369 | |||
370 | /* create the exported radio header */ | ||
371 | switch (priv->adapter->radiomode) { | ||
372 | case WLAN_RADIOMODE_NONE: | ||
373 | /* no radio header */ | ||
374 | /* chop the rxpd */ | ||
375 | skb_pull(skb, sizeof(struct rxpd)); | ||
376 | break; | ||
377 | |||
378 | case WLAN_RADIOMODE_RADIOTAP: | ||
379 | /* radiotap header */ | ||
380 | radiotap_hdr.hdr.it_version = 0; | ||
381 | /* XXX must check this value for pad */ | ||
382 | radiotap_hdr.hdr.it_pad = 0; | ||
383 | radiotap_hdr.hdr.it_len = sizeof(struct rx_radiotap_hdr); | ||
384 | radiotap_hdr.hdr.it_present = RX_RADIOTAP_PRESENT; | ||
385 | /* unknown values */ | ||
386 | radiotap_hdr.flags = 0; | ||
387 | radiotap_hdr.chan_freq = 0; | ||
388 | radiotap_hdr.chan_flags = 0; | ||
389 | radiotap_hdr.antenna = 0; | ||
390 | /* known values */ | ||
391 | radiotap_hdr.rate = convert_mv_rate_to_radiotap(prxpd->rx_rate); | ||
392 | /* XXX must check no carryout */ | ||
393 | radiotap_hdr.antsignal = prxpd->snr + prxpd->nf; | ||
394 | radiotap_hdr.rx_flags = 0; | ||
395 | if (!(prxpd->status & MRVDRV_RXPD_STATUS_OK)) | ||
396 | radiotap_hdr.rx_flags |= IEEE80211_RADIOTAP_F_RX_BADFCS; | ||
397 | //memset(radiotap_hdr.pad, 0x11, IEEE80211_RADIOTAP_HDRLEN - 18); | ||
398 | |||
399 | // lbs_dbg_hex1("RX radiomode packet BEF: ", skb->data, min(skb->len, 100)); | ||
400 | |||
401 | /* chop the rxpd */ | ||
402 | skb_pull(skb, sizeof(struct rxpd)); | ||
403 | |||
404 | /* add space for the new radio header */ | ||
405 | if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) && | ||
406 | pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, | ||
407 | GFP_ATOMIC)) { | ||
408 | lbs_pr_alert( "%s: couldn't pskb_expand_head\n", | ||
409 | __func__); | ||
410 | } | ||
411 | |||
412 | pradiotap_hdr = | ||
413 | (struct rx_radiotap_hdr *)skb_push(skb, | ||
414 | sizeof(struct | ||
415 | rx_radiotap_hdr)); | ||
416 | memcpy(pradiotap_hdr, &radiotap_hdr, | ||
417 | sizeof(struct rx_radiotap_hdr)); | ||
418 | //lbs_dbg_hex1("RX radiomode packet AFT: ", skb->data, min(skb->len, 100)); | ||
419 | break; | ||
420 | |||
421 | default: | ||
422 | /* unknown header */ | ||
423 | lbs_pr_alert( "Unknown radiomode (%i)\n", | ||
424 | priv->adapter->radiomode); | ||
425 | /* don't export any header */ | ||
426 | /* chop the rxpd */ | ||
427 | skb_pull(skb, sizeof(struct rxpd)); | ||
428 | break; | ||
429 | } | ||
430 | |||
431 | /* Take the data rate from the rxpd structure | ||
432 | * only if the rate is auto | ||
433 | */ | ||
434 | if (adapter->is_datarate_auto) { | ||
435 | adapter->datarate = libertas_index_to_data_rate(prxpd->rx_rate); | ||
436 | } | ||
437 | |||
438 | wlan_compute_rssi(priv, prxpd); | ||
439 | |||
440 | lbs_pr_debug(1, "RX Data: size of actual packet = %d\n", skb->len); | ||
441 | |||
442 | if (libertas_upload_rx_packet(priv, skb)) { | ||
443 | lbs_pr_debug(1, "RX error: libertas_upload_rx_packet " | ||
444 | "returns failure\n"); | ||
445 | ret = -1; | ||
446 | goto done; | ||
447 | } | ||
448 | |||
449 | priv->stats.rx_bytes += skb->len; | ||
450 | priv->stats.rx_packets++; | ||
451 | |||
452 | ret = 0; | ||
453 | done: | ||
454 | LEAVE(); | ||
455 | |||
456 | skb->protocol = __constant_htons(0x0019); /* ETH_P_80211_RAW */ | ||
457 | |||
458 | return (ret); | ||
459 | } | ||
diff --git a/drivers/net/wireless/libertas/sbi.h b/drivers/net/wireless/libertas/sbi.h new file mode 100644 index 000000000000..59d3a59ccef0 --- /dev/null +++ b/drivers/net/wireless/libertas/sbi.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /** | ||
2 | * This file contains IF layer definitions. | ||
3 | */ | ||
4 | |||
5 | #ifndef _SBI_H_ | ||
6 | #define _SBI_H_ | ||
7 | |||
8 | #include <linux/interrupt.h> | ||
9 | |||
10 | #include "defs.h" | ||
11 | |||
12 | /** INT status Bit Definition*/ | ||
13 | #define his_cmddnldrdy 0x01 | ||
14 | #define his_cardevent 0x02 | ||
15 | #define his_cmdupldrdy 0x04 | ||
16 | |||
17 | #ifndef DEV_NAME_LEN | ||
18 | #define DEV_NAME_LEN 32 | ||
19 | #endif | ||
20 | |||
21 | #define SBI_EVENT_CAUSE_SHIFT 3 | ||
22 | |||
23 | /* Probe and Check if the card is present*/ | ||
24 | int libertas_sbi_register_dev(wlan_private * priv); | ||
25 | int libertas_sbi_unregister_dev(wlan_private *); | ||
26 | int libertas_sbi_get_int_status(wlan_private * priv, u8 *); | ||
27 | int libertas_sbi_register(void); | ||
28 | void libertas_sbi_unregister(void); | ||
29 | int libertas_sbi_prog_firmware(wlan_private *); | ||
30 | |||
31 | int libertas_sbi_read_event_cause(wlan_private *); | ||
32 | int libertas_sbi_host_to_card(wlan_private * priv, u8 type, u8 * payload, u16 nb); | ||
33 | wlan_private *libertas_sbi_get_priv(void *card); | ||
34 | |||
35 | #ifdef ENABLE_PM | ||
36 | int libertas_sbi_suspend(wlan_private *); | ||
37 | int libertas_sbi_resume(wlan_private *); | ||
38 | #endif | ||
39 | |||
40 | #endif /* _SBI_H */ | ||
diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c new file mode 100644 index 000000000000..e18706238951 --- /dev/null +++ b/drivers/net/wireless/libertas/scan.c | |||
@@ -0,0 +1,2044 @@ | |||
1 | /* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ | ||
2 | /* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ | ||
3 | |||
4 | /** | ||
5 | * Functions implementing wlan scan IOCTL and firmware command APIs | ||
6 | * | ||
7 | * IOCTL handlers as well as command preperation and response routines | ||
8 | * for sending scan commands to the firmware. | ||
9 | */ | ||
10 | #include <linux/ctype.h> | ||
11 | #include <linux/if.h> | ||
12 | #include <linux/netdevice.h> | ||
13 | #include <linux/wireless.h> | ||
14 | |||
15 | #include <net/ieee80211.h> | ||
16 | #include <net/iw_handler.h> | ||
17 | |||
18 | #include "host.h" | ||
19 | #include "decl.h" | ||
20 | #include "dev.h" | ||
21 | #include "scan.h" | ||
22 | |||
23 | //! Approximate amount of data needed to pass a scan result back to iwlist | ||
24 | #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN \ | ||
25 | + IW_ESSID_MAX_SIZE \ | ||
26 | + IW_EV_UINT_LEN \ | ||
27 | + IW_EV_FREQ_LEN \ | ||
28 | + IW_EV_QUAL_LEN \ | ||
29 | + IW_ESSID_MAX_SIZE \ | ||
30 | + IW_EV_PARAM_LEN \ | ||
31 | + 40) /* 40 for WPAIE */ | ||
32 | |||
33 | //! Memory needed to store a max sized channel List TLV for a firmware scan | ||
34 | #define CHAN_TLV_MAX_SIZE (sizeof(struct mrvlietypesheader) \ | ||
35 | + (MRVDRV_MAX_CHANNELS_PER_SCAN \ | ||
36 | * sizeof(struct chanscanparamset))) | ||
37 | |||
38 | //! Memory needed to store a max number/size SSID TLV for a firmware scan | ||
39 | #define SSID_TLV_MAX_SIZE (1 * sizeof(struct mrvlietypes_ssidparamset)) | ||
40 | |||
41 | //! Maximum memory needed for a wlan_scan_cmd_config with all TLVs at max | ||
42 | #define MAX_SCAN_CFG_ALLOC (sizeof(struct wlan_scan_cmd_config) \ | ||
43 | + sizeof(struct mrvlietypes_numprobes) \ | ||
44 | + CHAN_TLV_MAX_SIZE \ | ||
45 | + SSID_TLV_MAX_SIZE) | ||
46 | |||
47 | //! The maximum number of channels the firmware can scan per command | ||
48 | #define MRVDRV_MAX_CHANNELS_PER_SCAN 14 | ||
49 | |||
50 | /** | ||
51 | * @brief Number of channels to scan per firmware scan command issuance. | ||
52 | * | ||
53 | * Number restricted to prevent hitting the limit on the amount of scan data | ||
54 | * returned in a single firmware scan command. | ||
55 | */ | ||
56 | #define MRVDRV_CHANNELS_PER_SCAN_CMD 4 | ||
57 | |||
58 | //! Scan time specified in the channel TLV for each channel for passive scans | ||
59 | #define MRVDRV_PASSIVE_SCAN_CHAN_TIME 100 | ||
60 | |||
61 | //! Scan time specified in the channel TLV for each channel for active scans | ||
62 | #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 | ||
63 | |||
64 | //! Macro to enable/disable SSID checking before storing a scan table | ||
65 | #ifdef DISCARD_BAD_SSID | ||
66 | #define CHECK_SSID_IS_VALID(x) ssid_valid(&bssidEntry.ssid) | ||
67 | #else | ||
68 | #define CHECK_SSID_IS_VALID(x) 1 | ||
69 | #endif | ||
70 | |||
71 | /** | ||
72 | * @brief Check if a scanned network compatible with the driver settings | ||
73 | * | ||
74 | * WEP WPA WPA2 ad-hoc encrypt Network | ||
75 | * enabled enabled enabled AES mode privacy WPA WPA2 Compatible | ||
76 | * 0 0 0 0 NONE 0 0 0 yes No security | ||
77 | * 1 0 0 0 NONE 1 0 0 yes Static WEP | ||
78 | * 0 1 0 0 x 1x 1 x yes WPA | ||
79 | * 0 0 1 0 x 1x x 1 yes WPA2 | ||
80 | * 0 0 0 1 NONE 1 0 0 yes Ad-hoc AES | ||
81 | * 0 0 0 0 !=NONE 1 0 0 yes Dynamic WEP | ||
82 | * | ||
83 | * | ||
84 | * @param adapter A pointer to wlan_adapter | ||
85 | * @param index Index in scantable to check against current driver settings | ||
86 | * @param mode Network mode: Infrastructure or IBSS | ||
87 | * | ||
88 | * @return Index in scantable, or error code if negative | ||
89 | */ | ||
90 | static int is_network_compatible(wlan_adapter * adapter, int index, int mode) | ||
91 | { | ||
92 | ENTER(); | ||
93 | |||
94 | if (adapter->scantable[index].inframode == mode) { | ||
95 | if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled | ||
96 | && !adapter->secinfo.WPAenabled | ||
97 | && !adapter->secinfo.WPA2enabled | ||
98 | && adapter->scantable[index].wpa_supplicant.wpa_ie[0] != | ||
99 | WPA_IE | ||
100 | && adapter->scantable[index].wpa2_supplicant.wpa_ie[0] != | ||
101 | WPA2_IE && adapter->secinfo.Encryptionmode == CIPHER_NONE | ||
102 | && !adapter->scantable[index].privacy) { | ||
103 | /* no security */ | ||
104 | LEAVE(); | ||
105 | return index; | ||
106 | } else if (adapter->secinfo.WEPstatus == wlan802_11WEPenabled | ||
107 | && !adapter->secinfo.WPAenabled | ||
108 | && !adapter->secinfo.WPA2enabled | ||
109 | && adapter->scantable[index].privacy) { | ||
110 | /* static WEP enabled */ | ||
111 | LEAVE(); | ||
112 | return index; | ||
113 | } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled | ||
114 | && adapter->secinfo.WPAenabled | ||
115 | && !adapter->secinfo.WPA2enabled | ||
116 | && (adapter->scantable[index].wpa_supplicant. | ||
117 | wpa_ie[0] | ||
118 | == WPA_IE) | ||
119 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | ||
120 | && adapter->scantable[index].privacy */ | ||
121 | ) { | ||
122 | /* WPA enabled */ | ||
123 | lbs_pr_debug(1, | ||
124 | "is_network_compatible() WPA: index=%d wpa_ie=%#x " | ||
125 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x " | ||
126 | "privacy=%#x\n", index, | ||
127 | adapter->scantable[index].wpa_supplicant. | ||
128 | wpa_ie[0], | ||
129 | adapter->scantable[index].wpa2_supplicant. | ||
130 | wpa_ie[0], | ||
131 | (adapter->secinfo.WEPstatus == | ||
132 | wlan802_11WEPenabled) ? "e" : "d", | ||
133 | (adapter->secinfo.WPAenabled) ? "e" : "d", | ||
134 | (adapter->secinfo.WPA2enabled) ? "e" : "d", | ||
135 | adapter->secinfo.Encryptionmode, | ||
136 | adapter->scantable[index].privacy); | ||
137 | LEAVE(); | ||
138 | return index; | ||
139 | } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled | ||
140 | && !adapter->secinfo.WPAenabled | ||
141 | && adapter->secinfo.WPA2enabled | ||
142 | && (adapter->scantable[index].wpa2_supplicant. | ||
143 | wpa_ie[0] | ||
144 | == WPA2_IE) | ||
145 | /* privacy bit may NOT be set in some APs like LinkSys WRT54G | ||
146 | && adapter->scantable[index].privacy */ | ||
147 | ) { | ||
148 | /* WPA2 enabled */ | ||
149 | lbs_pr_debug(1, | ||
150 | "is_network_compatible() WPA2: index=%d wpa_ie=%#x " | ||
151 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x " | ||
152 | "privacy=%#x\n", index, | ||
153 | adapter->scantable[index].wpa_supplicant. | ||
154 | wpa_ie[0], | ||
155 | adapter->scantable[index].wpa2_supplicant. | ||
156 | wpa_ie[0], | ||
157 | (adapter->secinfo.WEPstatus == | ||
158 | wlan802_11WEPenabled) ? "e" : "d", | ||
159 | (adapter->secinfo.WPAenabled) ? "e" : "d", | ||
160 | (adapter->secinfo.WPA2enabled) ? "e" : "d", | ||
161 | adapter->secinfo.Encryptionmode, | ||
162 | adapter->scantable[index].privacy); | ||
163 | LEAVE(); | ||
164 | return index; | ||
165 | } else if (adapter->secinfo.WEPstatus == wlan802_11WEPdisabled | ||
166 | && !adapter->secinfo.WPAenabled | ||
167 | && !adapter->secinfo.WPA2enabled | ||
168 | && (adapter->scantable[index].wpa_supplicant. | ||
169 | wpa_ie[0] | ||
170 | != WPA_IE) | ||
171 | && (adapter->scantable[index].wpa2_supplicant. | ||
172 | wpa_ie[0] | ||
173 | != WPA2_IE) | ||
174 | && adapter->secinfo.Encryptionmode != CIPHER_NONE | ||
175 | && adapter->scantable[index].privacy) { | ||
176 | /* dynamic WEP enabled */ | ||
177 | lbs_pr_debug(1, | ||
178 | "is_network_compatible() dynamic WEP: index=%d " | ||
179 | "wpa_ie=%#x wpa2_ie=%#x Encmode=%#x privacy=%#x\n", | ||
180 | index, | ||
181 | adapter->scantable[index].wpa_supplicant. | ||
182 | wpa_ie[0], | ||
183 | adapter->scantable[index].wpa2_supplicant. | ||
184 | wpa_ie[0], adapter->secinfo.Encryptionmode, | ||
185 | adapter->scantable[index].privacy); | ||
186 | LEAVE(); | ||
187 | return index; | ||
188 | } | ||
189 | |||
190 | /* security doesn't match */ | ||
191 | lbs_pr_debug(1, | ||
192 | "is_network_compatible() FAILED: index=%d wpa_ie=%#x " | ||
193 | "wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s Encmode=%#x privacy=%#x\n", | ||
194 | index, | ||
195 | adapter->scantable[index].wpa_supplicant.wpa_ie[0], | ||
196 | adapter->scantable[index].wpa2_supplicant.wpa_ie[0], | ||
197 | (adapter->secinfo.WEPstatus == | ||
198 | wlan802_11WEPenabled) ? "e" : "d", | ||
199 | (adapter->secinfo.WPAenabled) ? "e" : "d", | ||
200 | (adapter->secinfo.WPA2enabled) ? "e" : "d", | ||
201 | adapter->secinfo.Encryptionmode, | ||
202 | adapter->scantable[index].privacy); | ||
203 | LEAVE(); | ||
204 | return -ECONNREFUSED; | ||
205 | } | ||
206 | |||
207 | /* mode doesn't match */ | ||
208 | LEAVE(); | ||
209 | return -ENETUNREACH; | ||
210 | } | ||
211 | |||
212 | /** | ||
213 | * @brief This function validates a SSID as being able to be printed | ||
214 | * | ||
215 | * @param pssid SSID structure to validate | ||
216 | * | ||
217 | * @return TRUE or FALSE | ||
218 | */ | ||
219 | static u8 ssid_valid(struct WLAN_802_11_SSID *pssid) | ||
220 | { | ||
221 | int ssididx; | ||
222 | |||
223 | for (ssididx = 0; ssididx < pssid->ssidlength; ssididx++) { | ||
224 | if (!isprint(pssid->ssid[ssididx])) { | ||
225 | return 0; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | return 1; | ||
230 | } | ||
231 | |||
232 | /** | ||
233 | * @brief Post process the scan table after a new scan command has completed | ||
234 | * | ||
235 | * Inspect each entry of the scan table and try to find an entry that | ||
236 | * matches our current associated/joined network from the scan. If | ||
237 | * one is found, update the stored copy of the bssdescriptor for our | ||
238 | * current network. | ||
239 | * | ||
240 | * Debug dump the current scan table contents if compiled accordingly. | ||
241 | * | ||
242 | * @param priv A pointer to wlan_private structure | ||
243 | * | ||
244 | * @return void | ||
245 | */ | ||
246 | static void wlan_scan_process_results(wlan_private * priv) | ||
247 | { | ||
248 | wlan_adapter *adapter = priv->adapter; | ||
249 | int foundcurrent; | ||
250 | int i; | ||
251 | |||
252 | foundcurrent = 0; | ||
253 | |||
254 | if (adapter->connect_status == libertas_connected) { | ||
255 | /* try to find the current BSSID in the new scan list */ | ||
256 | for (i = 0; i < adapter->numinscantable; i++) { | ||
257 | if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, | ||
258 | &adapter->curbssparams.ssid) && | ||
259 | !memcmp(adapter->curbssparams.bssid, | ||
260 | adapter->scantable[i].macaddress, | ||
261 | ETH_ALEN)) { | ||
262 | foundcurrent = 1; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | if (foundcurrent) { | ||
267 | /* Make a copy of current BSSID descriptor */ | ||
268 | memcpy(&adapter->curbssparams.bssdescriptor, | ||
269 | &adapter->scantable[i], | ||
270 | sizeof(adapter->curbssparams.bssdescriptor)); | ||
271 | } | ||
272 | } | ||
273 | |||
274 | for (i = 0; i < adapter->numinscantable; i++) { | ||
275 | lbs_pr_debug(1, "Scan:(%02d) %02x:%02x:%02x:%02x:%02x:%02x, " | ||
276 | "RSSI[%03d], SSID[%s]\n", | ||
277 | i, | ||
278 | adapter->scantable[i].macaddress[0], | ||
279 | adapter->scantable[i].macaddress[1], | ||
280 | adapter->scantable[i].macaddress[2], | ||
281 | adapter->scantable[i].macaddress[3], | ||
282 | adapter->scantable[i].macaddress[4], | ||
283 | adapter->scantable[i].macaddress[5], | ||
284 | (s32) adapter->scantable[i].rssi, | ||
285 | adapter->scantable[i].ssid.ssid); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * @brief Create a channel list for the driver to scan based on region info | ||
291 | * | ||
292 | * Use the driver region/band information to construct a comprehensive list | ||
293 | * of channels to scan. This routine is used for any scan that is not | ||
294 | * provided a specific channel list to scan. | ||
295 | * | ||
296 | * @param priv A pointer to wlan_private structure | ||
297 | * @param scanchanlist Output parameter: resulting channel list to scan | ||
298 | * @param filteredscan Flag indicating whether or not a BSSID or SSID filter | ||
299 | * is being sent in the command to firmware. Used to | ||
300 | * increase the number of channels sent in a scan | ||
301 | * command and to disable the firmware channel scan | ||
302 | * filter. | ||
303 | * | ||
304 | * @return void | ||
305 | */ | ||
306 | static void wlan_scan_create_channel_list(wlan_private * priv, | ||
307 | struct chanscanparamset * scanchanlist, | ||
308 | u8 filteredscan) | ||
309 | { | ||
310 | |||
311 | wlan_adapter *adapter = priv->adapter; | ||
312 | struct region_channel *scanregion; | ||
313 | struct chan_freq_power *cfp; | ||
314 | int rgnidx; | ||
315 | int chanidx; | ||
316 | int nextchan; | ||
317 | u8 scantype; | ||
318 | |||
319 | chanidx = 0; | ||
320 | |||
321 | /* Set the default scan type to the user specified type, will later | ||
322 | * be changed to passive on a per channel basis if restricted by | ||
323 | * regulatory requirements (11d or 11h) | ||
324 | */ | ||
325 | scantype = adapter->scantype; | ||
326 | |||
327 | for (rgnidx = 0; rgnidx < ARRAY_SIZE(adapter->region_channel); rgnidx++) { | ||
328 | if (priv->adapter->enable11d && | ||
329 | adapter->connect_status != libertas_connected) { | ||
330 | /* Scan all the supported chan for the first scan */ | ||
331 | if (!adapter->universal_channel[rgnidx].valid) | ||
332 | continue; | ||
333 | scanregion = &adapter->universal_channel[rgnidx]; | ||
334 | |||
335 | /* clear the parsed_region_chan for the first scan */ | ||
336 | memset(&adapter->parsed_region_chan, 0x00, | ||
337 | sizeof(adapter->parsed_region_chan)); | ||
338 | } else { | ||
339 | if (!adapter->region_channel[rgnidx].valid) | ||
340 | continue; | ||
341 | scanregion = &adapter->region_channel[rgnidx]; | ||
342 | } | ||
343 | |||
344 | for (nextchan = 0; | ||
345 | nextchan < scanregion->nrcfp; nextchan++, chanidx++) { | ||
346 | |||
347 | cfp = scanregion->CFP + nextchan; | ||
348 | |||
349 | if (priv->adapter->enable11d) { | ||
350 | scantype = | ||
351 | libertas_get_scan_type_11d(cfp->channel, | ||
352 | &adapter-> | ||
353 | parsed_region_chan); | ||
354 | } | ||
355 | |||
356 | switch (scanregion->band) { | ||
357 | case BAND_B: | ||
358 | case BAND_G: | ||
359 | default: | ||
360 | scanchanlist[chanidx].radiotype = | ||
361 | cmd_scan_radio_type_bg; | ||
362 | break; | ||
363 | } | ||
364 | |||
365 | if (scantype == cmd_scan_type_passive) { | ||
366 | scanchanlist[chanidx].maxscantime = | ||
367 | cpu_to_le16 | ||
368 | (MRVDRV_PASSIVE_SCAN_CHAN_TIME); | ||
369 | scanchanlist[chanidx].chanscanmode.passivescan = | ||
370 | 1; | ||
371 | } else { | ||
372 | scanchanlist[chanidx].maxscantime = | ||
373 | cpu_to_le16 | ||
374 | (MRVDRV_ACTIVE_SCAN_CHAN_TIME); | ||
375 | scanchanlist[chanidx].chanscanmode.passivescan = | ||
376 | 0; | ||
377 | } | ||
378 | |||
379 | scanchanlist[chanidx].channumber = cfp->channel; | ||
380 | |||
381 | if (filteredscan) { | ||
382 | scanchanlist[chanidx].chanscanmode. | ||
383 | disablechanfilt = 1; | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | |||
389 | /** | ||
390 | * @brief Construct a wlan_scan_cmd_config structure to use in issue scan cmds | ||
391 | * | ||
392 | * Application layer or other functions can invoke wlan_scan_networks | ||
393 | * with a scan configuration supplied in a wlan_ioctl_user_scan_cfg struct. | ||
394 | * This structure is used as the basis of one or many wlan_scan_cmd_config | ||
395 | * commands that are sent to the command processing module and sent to | ||
396 | * firmware. | ||
397 | * | ||
398 | * Create a wlan_scan_cmd_config based on the following user supplied | ||
399 | * parameters (if present): | ||
400 | * - SSID filter | ||
401 | * - BSSID filter | ||
402 | * - Number of Probes to be sent | ||
403 | * - channel list | ||
404 | * | ||
405 | * If the SSID or BSSID filter is not present, disable/clear the filter. | ||
406 | * If the number of probes is not set, use the adapter default setting | ||
407 | * Qualify the channel | ||
408 | * | ||
409 | * @param priv A pointer to wlan_private structure | ||
410 | * @param puserscanin NULL or pointer to scan configuration parameters | ||
411 | * @param ppchantlvout Output parameter: Pointer to the start of the | ||
412 | * channel TLV portion of the output scan config | ||
413 | * @param pscanchanlist Output parameter: Pointer to the resulting channel | ||
414 | * list to scan | ||
415 | * @param pmaxchanperscan Output parameter: Number of channels to scan for | ||
416 | * each issuance of the firmware scan command | ||
417 | * @param pfilteredscan Output parameter: Flag indicating whether or not | ||
418 | * a BSSID or SSID filter is being sent in the | ||
419 | * command to firmware. Used to increase the number | ||
420 | * of channels sent in a scan command and to | ||
421 | * disable the firmware channel scan filter. | ||
422 | * @param pscancurrentonly Output parameter: Flag indicating whether or not | ||
423 | * we are only scanning our current active channel | ||
424 | * | ||
425 | * @return resulting scan configuration | ||
426 | */ | ||
427 | static struct wlan_scan_cmd_config * | ||
428 | wlan_scan_setup_scan_config(wlan_private * priv, | ||
429 | const struct wlan_ioctl_user_scan_cfg * puserscanin, | ||
430 | struct mrvlietypes_chanlistparamset ** ppchantlvout, | ||
431 | struct chanscanparamset * pscanchanlist, | ||
432 | int *pmaxchanperscan, | ||
433 | u8 * pfilteredscan, | ||
434 | u8 * pscancurrentonly) | ||
435 | { | ||
436 | wlan_adapter *adapter = priv->adapter; | ||
437 | const u8 zeromac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 }; | ||
438 | struct mrvlietypes_numprobes *pnumprobestlv; | ||
439 | struct mrvlietypes_ssidparamset *pssidtlv; | ||
440 | struct wlan_scan_cmd_config * pscancfgout = NULL; | ||
441 | u8 *ptlvpos; | ||
442 | u16 numprobes; | ||
443 | u16 ssidlen; | ||
444 | int chanidx; | ||
445 | int scantype; | ||
446 | int scandur; | ||
447 | int channel; | ||
448 | int radiotype; | ||
449 | |||
450 | pscancfgout = kzalloc(MAX_SCAN_CFG_ALLOC, GFP_KERNEL); | ||
451 | if (pscancfgout == NULL) | ||
452 | goto out; | ||
453 | |||
454 | /* The tlvbufferlen is calculated for each scan command. The TLVs added | ||
455 | * in this routine will be preserved since the routine that sends | ||
456 | * the command will append channelTLVs at *ppchantlvout. The difference | ||
457 | * between the *ppchantlvout and the tlvbuffer start will be used | ||
458 | * to calculate the size of anything we add in this routine. | ||
459 | */ | ||
460 | pscancfgout->tlvbufferlen = 0; | ||
461 | |||
462 | /* Running tlv pointer. Assigned to ppchantlvout at end of function | ||
463 | * so later routines know where channels can be added to the command buf | ||
464 | */ | ||
465 | ptlvpos = pscancfgout->tlvbuffer; | ||
466 | |||
467 | /* | ||
468 | * Set the initial scan paramters for progressive scanning. If a specific | ||
469 | * BSSID or SSID is used, the number of channels in the scan command | ||
470 | * will be increased to the absolute maximum | ||
471 | */ | ||
472 | *pmaxchanperscan = MRVDRV_CHANNELS_PER_SCAN_CMD; | ||
473 | |||
474 | /* Initialize the scan as un-filtered by firmware, set to TRUE below if | ||
475 | * a SSID or BSSID filter is sent in the command | ||
476 | */ | ||
477 | *pfilteredscan = 0; | ||
478 | |||
479 | /* Initialize the scan as not being only on the current channel. If | ||
480 | * the channel list is customized, only contains one channel, and | ||
481 | * is the active channel, this is set true and data flow is not halted. | ||
482 | */ | ||
483 | *pscancurrentonly = 0; | ||
484 | |||
485 | if (puserscanin) { | ||
486 | |||
487 | /* Set the bss type scan filter, use adapter setting if unset */ | ||
488 | pscancfgout->bsstype = | ||
489 | (puserscanin->bsstype ? puserscanin->bsstype : adapter-> | ||
490 | scanmode); | ||
491 | |||
492 | /* Set the number of probes to send, use adapter setting if unset */ | ||
493 | numprobes = (puserscanin->numprobes ? puserscanin->numprobes : | ||
494 | adapter->scanprobes); | ||
495 | |||
496 | /* | ||
497 | * Set the BSSID filter to the incoming configuration, | ||
498 | * if non-zero. If not set, it will remain disabled (all zeros). | ||
499 | */ | ||
500 | memcpy(pscancfgout->specificBSSID, | ||
501 | puserscanin->specificBSSID, | ||
502 | sizeof(pscancfgout->specificBSSID)); | ||
503 | |||
504 | ssidlen = strlen(puserscanin->specificSSID); | ||
505 | |||
506 | if (ssidlen) { | ||
507 | pssidtlv = | ||
508 | (struct mrvlietypes_ssidparamset *) pscancfgout-> | ||
509 | tlvbuffer; | ||
510 | pssidtlv->header.type = cpu_to_le16(TLV_TYPE_SSID); | ||
511 | pssidtlv->header.len = cpu_to_le16(ssidlen); | ||
512 | memcpy(pssidtlv->ssid, puserscanin->specificSSID, | ||
513 | ssidlen); | ||
514 | ptlvpos += sizeof(pssidtlv->header) + ssidlen; | ||
515 | } | ||
516 | |||
517 | /* | ||
518 | * The default number of channels sent in the command is low to | ||
519 | * ensure the response buffer from the firmware does not truncate | ||
520 | * scan results. That is not an issue with an SSID or BSSID | ||
521 | * filter applied to the scan results in the firmware. | ||
522 | */ | ||
523 | if (ssidlen || (memcmp(pscancfgout->specificBSSID, | ||
524 | &zeromac, sizeof(zeromac)) != 0)) { | ||
525 | *pmaxchanperscan = MRVDRV_MAX_CHANNELS_PER_SCAN; | ||
526 | *pfilteredscan = 1; | ||
527 | } | ||
528 | } else { | ||
529 | pscancfgout->bsstype = adapter->scanmode; | ||
530 | numprobes = adapter->scanprobes; | ||
531 | } | ||
532 | |||
533 | /* If the input config or adapter has the number of Probes set, add tlv */ | ||
534 | if (numprobes) { | ||
535 | pnumprobestlv = (struct mrvlietypes_numprobes *) ptlvpos; | ||
536 | pnumprobestlv->header.type = | ||
537 | cpu_to_le16(TLV_TYPE_NUMPROBES); | ||
538 | pnumprobestlv->header.len = sizeof(pnumprobestlv->numprobes); | ||
539 | pnumprobestlv->numprobes = cpu_to_le16(numprobes); | ||
540 | |||
541 | ptlvpos += | ||
542 | sizeof(pnumprobestlv->header) + pnumprobestlv->header.len; | ||
543 | |||
544 | pnumprobestlv->header.len = | ||
545 | cpu_to_le16(pnumprobestlv->header.len); | ||
546 | } | ||
547 | |||
548 | /* | ||
549 | * Set the output for the channel TLV to the address in the tlv buffer | ||
550 | * past any TLVs that were added in this fuction (SSID, numprobes). | ||
551 | * channel TLVs will be added past this for each scan command, preserving | ||
552 | * the TLVs that were previously added. | ||
553 | */ | ||
554 | *ppchantlvout = (struct mrvlietypes_chanlistparamset *) ptlvpos; | ||
555 | |||
556 | if (puserscanin && puserscanin->chanlist[0].channumber) { | ||
557 | |||
558 | lbs_pr_debug(1, "Scan: Using supplied channel list\n"); | ||
559 | |||
560 | for (chanidx = 0; | ||
561 | chanidx < WLAN_IOCTL_USER_SCAN_CHAN_MAX | ||
562 | && puserscanin->chanlist[chanidx].channumber; chanidx++) { | ||
563 | |||
564 | channel = puserscanin->chanlist[chanidx].channumber; | ||
565 | (pscanchanlist + chanidx)->channumber = channel; | ||
566 | |||
567 | radiotype = puserscanin->chanlist[chanidx].radiotype; | ||
568 | (pscanchanlist + chanidx)->radiotype = radiotype; | ||
569 | |||
570 | scantype = puserscanin->chanlist[chanidx].scantype; | ||
571 | |||
572 | if (scantype == cmd_scan_type_passive) { | ||
573 | (pscanchanlist + | ||
574 | chanidx)->chanscanmode.passivescan = 1; | ||
575 | } else { | ||
576 | (pscanchanlist + | ||
577 | chanidx)->chanscanmode.passivescan = 0; | ||
578 | } | ||
579 | |||
580 | if (puserscanin->chanlist[chanidx].scantime) { | ||
581 | scandur = | ||
582 | puserscanin->chanlist[chanidx].scantime; | ||
583 | } else { | ||
584 | if (scantype == cmd_scan_type_passive) { | ||
585 | scandur = MRVDRV_PASSIVE_SCAN_CHAN_TIME; | ||
586 | } else { | ||
587 | scandur = MRVDRV_ACTIVE_SCAN_CHAN_TIME; | ||
588 | } | ||
589 | } | ||
590 | |||
591 | (pscanchanlist + chanidx)->minscantime = | ||
592 | cpu_to_le16(scandur); | ||
593 | (pscanchanlist + chanidx)->maxscantime = | ||
594 | cpu_to_le16(scandur); | ||
595 | } | ||
596 | |||
597 | /* Check if we are only scanning the current channel */ | ||
598 | if ((chanidx == 1) && (puserscanin->chanlist[0].channumber | ||
599 | == | ||
600 | priv->adapter->curbssparams.channel)) { | ||
601 | *pscancurrentonly = 1; | ||
602 | lbs_pr_debug(1, "Scan: Scanning current channel only"); | ||
603 | } | ||
604 | |||
605 | } else { | ||
606 | lbs_pr_debug(1, "Scan: Creating full region channel list\n"); | ||
607 | wlan_scan_create_channel_list(priv, pscanchanlist, | ||
608 | *pfilteredscan); | ||
609 | } | ||
610 | |||
611 | out: | ||
612 | return pscancfgout; | ||
613 | } | ||
614 | |||
615 | /** | ||
616 | * @brief Construct and send multiple scan config commands to the firmware | ||
617 | * | ||
618 | * Previous routines have created a wlan_scan_cmd_config with any requested | ||
619 | * TLVs. This function splits the channel TLV into maxchanperscan lists | ||
620 | * and sends the portion of the channel TLV along with the other TLVs | ||
621 | * to the wlan_cmd routines for execution in the firmware. | ||
622 | * | ||
623 | * @param priv A pointer to wlan_private structure | ||
624 | * @param maxchanperscan Maximum number channels to be included in each | ||
625 | * scan command sent to firmware | ||
626 | * @param filteredscan Flag indicating whether or not a BSSID or SSID | ||
627 | * filter is being used for the firmware command | ||
628 | * scan command sent to firmware | ||
629 | * @param pscancfgout Scan configuration used for this scan. | ||
630 | * @param pchantlvout Pointer in the pscancfgout where the channel TLV | ||
631 | * should start. This is past any other TLVs that | ||
632 | * must be sent down in each firmware command. | ||
633 | * @param pscanchanlist List of channels to scan in maxchanperscan segments | ||
634 | * | ||
635 | * @return 0 or error return otherwise | ||
636 | */ | ||
637 | static int wlan_scan_channel_list(wlan_private * priv, | ||
638 | int maxchanperscan, | ||
639 | u8 filteredscan, | ||
640 | struct wlan_scan_cmd_config * pscancfgout, | ||
641 | struct mrvlietypes_chanlistparamset * pchantlvout, | ||
642 | struct chanscanparamset * pscanchanlist) | ||
643 | { | ||
644 | struct chanscanparamset *ptmpchan; | ||
645 | struct chanscanparamset *pstartchan; | ||
646 | u8 scanband; | ||
647 | int doneearly; | ||
648 | int tlvidx; | ||
649 | int ret = 0; | ||
650 | |||
651 | ENTER(); | ||
652 | |||
653 | if (pscancfgout == 0 || pchantlvout == 0 || pscanchanlist == 0) { | ||
654 | lbs_pr_debug(1, "Scan: Null detect: %p, %p, %p\n", | ||
655 | pscancfgout, pchantlvout, pscanchanlist); | ||
656 | return -1; | ||
657 | } | ||
658 | |||
659 | pchantlvout->header.type = cpu_to_le16(TLV_TYPE_CHANLIST); | ||
660 | |||
661 | /* Set the temp channel struct pointer to the start of the desired list */ | ||
662 | ptmpchan = pscanchanlist; | ||
663 | |||
664 | /* Loop through the desired channel list, sending a new firmware scan | ||
665 | * commands for each maxchanperscan channels (or for 1,6,11 individually | ||
666 | * if configured accordingly) | ||
667 | */ | ||
668 | while (ptmpchan->channumber) { | ||
669 | |||
670 | tlvidx = 0; | ||
671 | pchantlvout->header.len = 0; | ||
672 | scanband = ptmpchan->radiotype; | ||
673 | pstartchan = ptmpchan; | ||
674 | doneearly = 0; | ||
675 | |||
676 | /* Construct the channel TLV for the scan command. Continue to | ||
677 | * insert channel TLVs until: | ||
678 | * - the tlvidx hits the maximum configured per scan command | ||
679 | * - the next channel to insert is 0 (end of desired channel list) | ||
680 | * - doneearly is set (controlling individual scanning of 1,6,11) | ||
681 | */ | ||
682 | while (tlvidx < maxchanperscan && ptmpchan->channumber | ||
683 | && !doneearly) { | ||
684 | |||
685 | lbs_pr_debug(1, | ||
686 | "Scan: Chan(%3d), Radio(%d), mode(%d,%d), Dur(%d)\n", | ||
687 | ptmpchan->channumber, ptmpchan->radiotype, | ||
688 | ptmpchan->chanscanmode.passivescan, | ||
689 | ptmpchan->chanscanmode.disablechanfilt, | ||
690 | ptmpchan->maxscantime); | ||
691 | |||
692 | /* Copy the current channel TLV to the command being prepared */ | ||
693 | memcpy(pchantlvout->chanscanparam + tlvidx, | ||
694 | ptmpchan, sizeof(pchantlvout->chanscanparam)); | ||
695 | |||
696 | /* Increment the TLV header length by the size appended */ | ||
697 | pchantlvout->header.len += | ||
698 | sizeof(pchantlvout->chanscanparam); | ||
699 | |||
700 | /* | ||
701 | * The tlv buffer length is set to the number of bytes of the | ||
702 | * between the channel tlv pointer and the start of the | ||
703 | * tlv buffer. This compensates for any TLVs that were appended | ||
704 | * before the channel list. | ||
705 | */ | ||
706 | pscancfgout->tlvbufferlen = ((u8 *) pchantlvout | ||
707 | - pscancfgout->tlvbuffer); | ||
708 | |||
709 | /* Add the size of the channel tlv header and the data length */ | ||
710 | pscancfgout->tlvbufferlen += | ||
711 | (sizeof(pchantlvout->header) | ||
712 | + pchantlvout->header.len); | ||
713 | |||
714 | /* Increment the index to the channel tlv we are constructing */ | ||
715 | tlvidx++; | ||
716 | |||
717 | doneearly = 0; | ||
718 | |||
719 | /* Stop the loop if the *current* channel is in the 1,6,11 set | ||
720 | * and we are not filtering on a BSSID or SSID. | ||
721 | */ | ||
722 | if (!filteredscan && (ptmpchan->channumber == 1 | ||
723 | || ptmpchan->channumber == 6 | ||
724 | || ptmpchan->channumber == 11)) { | ||
725 | doneearly = 1; | ||
726 | } | ||
727 | |||
728 | /* Increment the tmp pointer to the next channel to be scanned */ | ||
729 | ptmpchan++; | ||
730 | |||
731 | /* Stop the loop if the *next* channel is in the 1,6,11 set. | ||
732 | * This will cause it to be the only channel scanned on the next | ||
733 | * interation | ||
734 | */ | ||
735 | if (!filteredscan && (ptmpchan->channumber == 1 | ||
736 | || ptmpchan->channumber == 6 | ||
737 | || ptmpchan->channumber == 11)) { | ||
738 | doneearly = 1; | ||
739 | } | ||
740 | } | ||
741 | |||
742 | /* Send the scan command to the firmware with the specified cfg */ | ||
743 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_scan, 0, | ||
744 | 0, 0, pscancfgout); | ||
745 | } | ||
746 | |||
747 | LEAVE(); | ||
748 | return ret; | ||
749 | } | ||
750 | |||
751 | /** | ||
752 | * @brief Internal function used to start a scan based on an input config | ||
753 | * | ||
754 | * Use the input user scan configuration information when provided in | ||
755 | * order to send the appropriate scan commands to firmware to populate or | ||
756 | * update the internal driver scan table | ||
757 | * | ||
758 | * @param priv A pointer to wlan_private structure | ||
759 | * @param puserscanin Pointer to the input configuration for the requested | ||
760 | * scan. | ||
761 | * | ||
762 | * @return 0 or < 0 if error | ||
763 | */ | ||
764 | int wlan_scan_networks(wlan_private * priv, | ||
765 | const struct wlan_ioctl_user_scan_cfg * puserscanin) | ||
766 | { | ||
767 | wlan_adapter *adapter = priv->adapter; | ||
768 | struct mrvlietypes_chanlistparamset *pchantlvout; | ||
769 | struct chanscanparamset * scan_chan_list = NULL; | ||
770 | struct wlan_scan_cmd_config * scan_cfg = NULL; | ||
771 | u8 keeppreviousscan; | ||
772 | u8 filteredscan; | ||
773 | u8 scancurrentchanonly; | ||
774 | int maxchanperscan; | ||
775 | int ret; | ||
776 | |||
777 | ENTER(); | ||
778 | |||
779 | scan_chan_list = kzalloc(sizeof(struct chanscanparamset) * | ||
780 | WLAN_IOCTL_USER_SCAN_CHAN_MAX, GFP_KERNEL); | ||
781 | if (scan_chan_list == NULL) { | ||
782 | ret = -ENOMEM; | ||
783 | goto out; | ||
784 | } | ||
785 | |||
786 | scan_cfg = wlan_scan_setup_scan_config(priv, | ||
787 | puserscanin, | ||
788 | &pchantlvout, | ||
789 | scan_chan_list, | ||
790 | &maxchanperscan, | ||
791 | &filteredscan, | ||
792 | &scancurrentchanonly); | ||
793 | if (scan_cfg == NULL) { | ||
794 | ret = -ENOMEM; | ||
795 | goto out; | ||
796 | } | ||
797 | |||
798 | keeppreviousscan = 0; | ||
799 | |||
800 | if (puserscanin) { | ||
801 | keeppreviousscan = puserscanin->keeppreviousscan; | ||
802 | } | ||
803 | |||
804 | if (!keeppreviousscan) { | ||
805 | memset(adapter->scantable, 0x00, | ||
806 | sizeof(struct bss_descriptor) * MRVDRV_MAX_BSSID_LIST); | ||
807 | adapter->numinscantable = 0; | ||
808 | } | ||
809 | |||
810 | /* Keep the data path active if we are only scanning our current channel */ | ||
811 | if (!scancurrentchanonly) { | ||
812 | netif_stop_queue(priv->wlan_dev.netdev); | ||
813 | netif_carrier_off(priv->wlan_dev.netdev); | ||
814 | } | ||
815 | |||
816 | ret = wlan_scan_channel_list(priv, | ||
817 | maxchanperscan, | ||
818 | filteredscan, | ||
819 | scan_cfg, | ||
820 | pchantlvout, | ||
821 | scan_chan_list); | ||
822 | |||
823 | /* Process the resulting scan table: | ||
824 | * - Remove any bad ssids | ||
825 | * - Update our current BSS information from scan data | ||
826 | */ | ||
827 | wlan_scan_process_results(priv); | ||
828 | |||
829 | if (priv->adapter->connect_status == libertas_connected) { | ||
830 | netif_carrier_on(priv->wlan_dev.netdev); | ||
831 | netif_wake_queue(priv->wlan_dev.netdev); | ||
832 | } | ||
833 | |||
834 | out: | ||
835 | if (scan_cfg) | ||
836 | kfree(scan_cfg); | ||
837 | |||
838 | if (scan_chan_list) | ||
839 | kfree(scan_chan_list); | ||
840 | |||
841 | LEAVE(); | ||
842 | return ret; | ||
843 | } | ||
844 | |||
845 | /** | ||
846 | * @brief Inspect the scan response buffer for pointers to expected TLVs | ||
847 | * | ||
848 | * TLVs can be included at the end of the scan response BSS information. | ||
849 | * Parse the data in the buffer for pointers to TLVs that can potentially | ||
850 | * be passed back in the response | ||
851 | * | ||
852 | * @param ptlv Pointer to the start of the TLV buffer to parse | ||
853 | * @param tlvbufsize size of the TLV buffer | ||
854 | * @param ptsftlv Output parameter: Pointer to the TSF TLV if found | ||
855 | * | ||
856 | * @return void | ||
857 | */ | ||
858 | static | ||
859 | void wlan_ret_802_11_scan_get_tlv_ptrs(struct mrvlietypes_data * ptlv, | ||
860 | int tlvbufsize, | ||
861 | struct mrvlietypes_tsftimestamp ** ptsftlv) | ||
862 | { | ||
863 | struct mrvlietypes_data *pcurrenttlv; | ||
864 | int tlvbufleft; | ||
865 | u16 tlvtype; | ||
866 | u16 tlvlen; | ||
867 | |||
868 | pcurrenttlv = ptlv; | ||
869 | tlvbufleft = tlvbufsize; | ||
870 | *ptsftlv = NULL; | ||
871 | |||
872 | lbs_pr_debug(1, "SCAN_RESP: tlvbufsize = %d\n", tlvbufsize); | ||
873 | lbs_dbg_hex("SCAN_RESP: TLV Buf", (u8 *) ptlv, tlvbufsize); | ||
874 | |||
875 | while (tlvbufleft >= sizeof(struct mrvlietypesheader)) { | ||
876 | tlvtype = le16_to_cpu(pcurrenttlv->header.type); | ||
877 | tlvlen = le16_to_cpu(pcurrenttlv->header.len); | ||
878 | |||
879 | switch (tlvtype) { | ||
880 | case TLV_TYPE_TSFTIMESTAMP: | ||
881 | *ptsftlv = (struct mrvlietypes_tsftimestamp *) pcurrenttlv; | ||
882 | break; | ||
883 | |||
884 | default: | ||
885 | lbs_pr_debug(1, "SCAN_RESP: Unhandled TLV = %d\n", | ||
886 | tlvtype); | ||
887 | /* Give up, this seems corrupted */ | ||
888 | return; | ||
889 | } /* switch */ | ||
890 | |||
891 | tlvbufleft -= (sizeof(ptlv->header) + tlvlen); | ||
892 | pcurrenttlv = | ||
893 | (struct mrvlietypes_data *) (pcurrenttlv->Data + tlvlen); | ||
894 | } /* while */ | ||
895 | } | ||
896 | |||
897 | /** | ||
898 | * @brief Interpret a BSS scan response returned from the firmware | ||
899 | * | ||
900 | * Parse the various fixed fields and IEs passed back for a a BSS probe | ||
901 | * response or beacon from the scan command. Record information as needed | ||
902 | * in the scan table struct bss_descriptor for that entry. | ||
903 | * | ||
904 | * @param pBSSIDEntry Output parameter: Pointer to the BSS Entry | ||
905 | * | ||
906 | * @return 0 or -1 | ||
907 | */ | ||
908 | static int InterpretBSSDescriptionWithIE(struct bss_descriptor * pBSSEntry, | ||
909 | u8 ** pbeaconinfo, int *bytesleft) | ||
910 | { | ||
911 | enum ieeetypes_elementid elemID; | ||
912 | struct ieeetypes_fhparamset *pFH; | ||
913 | struct ieeetypes_dsparamset *pDS; | ||
914 | struct ieeetypes_cfparamset *pCF; | ||
915 | struct ieeetypes_ibssparamset *pibss; | ||
916 | struct ieeetypes_capinfo *pcap; | ||
917 | struct WLAN_802_11_FIXED_IEs fixedie; | ||
918 | u8 *pcurrentptr; | ||
919 | u8 *pRate; | ||
920 | u8 elemlen; | ||
921 | u8 bytestocopy; | ||
922 | u8 ratesize; | ||
923 | u16 beaconsize; | ||
924 | u8 founddatarateie; | ||
925 | int bytesleftforcurrentbeacon; | ||
926 | |||
927 | struct WPA_SUPPLICANT *pwpa_supplicant; | ||
928 | struct WPA_SUPPLICANT *pwpa2_supplicant; | ||
929 | struct IE_WPA *pIe; | ||
930 | const u8 oui01[4] = { 0x00, 0x50, 0xf2, 0x01 }; | ||
931 | |||
932 | struct ieeetypes_countryinfoset *pcountryinfo; | ||
933 | |||
934 | ENTER(); | ||
935 | |||
936 | founddatarateie = 0; | ||
937 | ratesize = 0; | ||
938 | beaconsize = 0; | ||
939 | |||
940 | if (*bytesleft >= sizeof(beaconsize)) { | ||
941 | /* Extract & convert beacon size from the command buffer */ | ||
942 | memcpy(&beaconsize, *pbeaconinfo, sizeof(beaconsize)); | ||
943 | beaconsize = le16_to_cpu(beaconsize); | ||
944 | *bytesleft -= sizeof(beaconsize); | ||
945 | *pbeaconinfo += sizeof(beaconsize); | ||
946 | } | ||
947 | |||
948 | if (beaconsize == 0 || beaconsize > *bytesleft) { | ||
949 | |||
950 | *pbeaconinfo += *bytesleft; | ||
951 | *bytesleft = 0; | ||
952 | |||
953 | return -1; | ||
954 | } | ||
955 | |||
956 | /* Initialize the current working beacon pointer for this BSS iteration */ | ||
957 | pcurrentptr = *pbeaconinfo; | ||
958 | |||
959 | /* Advance the return beacon pointer past the current beacon */ | ||
960 | *pbeaconinfo += beaconsize; | ||
961 | *bytesleft -= beaconsize; | ||
962 | |||
963 | bytesleftforcurrentbeacon = beaconsize; | ||
964 | |||
965 | pwpa_supplicant = &pBSSEntry->wpa_supplicant; | ||
966 | pwpa2_supplicant = &pBSSEntry->wpa2_supplicant; | ||
967 | |||
968 | memcpy(pBSSEntry->macaddress, pcurrentptr, ETH_ALEN); | ||
969 | lbs_pr_debug(1, "InterpretIE: AP MAC Addr-%x:%x:%x:%x:%x:%x\n", | ||
970 | pBSSEntry->macaddress[0], pBSSEntry->macaddress[1], | ||
971 | pBSSEntry->macaddress[2], pBSSEntry->macaddress[3], | ||
972 | pBSSEntry->macaddress[4], pBSSEntry->macaddress[5]); | ||
973 | |||
974 | pcurrentptr += ETH_ALEN; | ||
975 | bytesleftforcurrentbeacon -= ETH_ALEN; | ||
976 | |||
977 | if (bytesleftforcurrentbeacon < 12) { | ||
978 | lbs_pr_debug(1, "InterpretIE: Not enough bytes left\n"); | ||
979 | return -1; | ||
980 | } | ||
981 | |||
982 | /* | ||
983 | * next 4 fields are RSSI, time stamp, beacon interval, | ||
984 | * and capability information | ||
985 | */ | ||
986 | |||
987 | /* RSSI is 1 byte long */ | ||
988 | pBSSEntry->rssi = le32_to_cpu((long)(*pcurrentptr)); | ||
989 | lbs_pr_debug(1, "InterpretIE: RSSI=%02X\n", *pcurrentptr); | ||
990 | pcurrentptr += 1; | ||
991 | bytesleftforcurrentbeacon -= 1; | ||
992 | |||
993 | /* time stamp is 8 bytes long */ | ||
994 | memcpy(fixedie.timestamp, pcurrentptr, 8); | ||
995 | memcpy(pBSSEntry->timestamp, pcurrentptr, 8); | ||
996 | pcurrentptr += 8; | ||
997 | bytesleftforcurrentbeacon -= 8; | ||
998 | |||
999 | /* beacon interval is 2 bytes long */ | ||
1000 | memcpy(&fixedie.beaconinterval, pcurrentptr, 2); | ||
1001 | pBSSEntry->beaconperiod = le16_to_cpu(fixedie.beaconinterval); | ||
1002 | pcurrentptr += 2; | ||
1003 | bytesleftforcurrentbeacon -= 2; | ||
1004 | |||
1005 | /* capability information is 2 bytes long */ | ||
1006 | memcpy(&fixedie.capabilities, pcurrentptr, 2); | ||
1007 | lbs_pr_debug(1, "InterpretIE: fixedie.capabilities=0x%X\n", | ||
1008 | fixedie.capabilities); | ||
1009 | fixedie.capabilities = le16_to_cpu(fixedie.capabilities); | ||
1010 | pcap = (struct ieeetypes_capinfo *) & fixedie.capabilities; | ||
1011 | memcpy(&pBSSEntry->cap, pcap, sizeof(struct ieeetypes_capinfo)); | ||
1012 | pcurrentptr += 2; | ||
1013 | bytesleftforcurrentbeacon -= 2; | ||
1014 | |||
1015 | /* rest of the current buffer are IE's */ | ||
1016 | lbs_pr_debug(1, "InterpretIE: IElength for this AP = %d\n", | ||
1017 | bytesleftforcurrentbeacon); | ||
1018 | |||
1019 | lbs_dbg_hex("InterpretIE: IE info", (u8 *) pcurrentptr, | ||
1020 | bytesleftforcurrentbeacon); | ||
1021 | |||
1022 | if (pcap->privacy) { | ||
1023 | lbs_pr_debug(1, "InterpretIE: AP WEP enabled\n"); | ||
1024 | pBSSEntry->privacy = wlan802_11privfilter8021xWEP; | ||
1025 | } else { | ||
1026 | pBSSEntry->privacy = wlan802_11privfilteracceptall; | ||
1027 | } | ||
1028 | |||
1029 | if (pcap->ibss == 1) { | ||
1030 | pBSSEntry->inframode = wlan802_11ibss; | ||
1031 | } else { | ||
1032 | pBSSEntry->inframode = wlan802_11infrastructure; | ||
1033 | } | ||
1034 | |||
1035 | /* process variable IE */ | ||
1036 | while (bytesleftforcurrentbeacon >= 2) { | ||
1037 | elemID = (enum ieeetypes_elementid) (*((u8 *) pcurrentptr)); | ||
1038 | elemlen = *((u8 *) pcurrentptr + 1); | ||
1039 | |||
1040 | if (bytesleftforcurrentbeacon < elemlen) { | ||
1041 | lbs_pr_debug(1, "InterpretIE: error in processing IE, " | ||
1042 | "bytes left < IE length\n"); | ||
1043 | bytesleftforcurrentbeacon = 0; | ||
1044 | continue; | ||
1045 | } | ||
1046 | |||
1047 | switch (elemID) { | ||
1048 | |||
1049 | case SSID: | ||
1050 | pBSSEntry->ssid.ssidlength = elemlen; | ||
1051 | memcpy(pBSSEntry->ssid.ssid, (pcurrentptr + 2), | ||
1052 | elemlen); | ||
1053 | lbs_pr_debug(1, "ssid: %32s", pBSSEntry->ssid.ssid); | ||
1054 | break; | ||
1055 | |||
1056 | case SUPPORTED_RATES: | ||
1057 | memcpy(pBSSEntry->datarates, (pcurrentptr + 2), | ||
1058 | elemlen); | ||
1059 | memmove(pBSSEntry->libertas_supported_rates, (pcurrentptr + 2), | ||
1060 | elemlen); | ||
1061 | ratesize = elemlen; | ||
1062 | founddatarateie = 1; | ||
1063 | break; | ||
1064 | |||
1065 | case EXTRA_IE: | ||
1066 | lbs_pr_debug(1, "InterpretIE: EXTRA_IE Found!\n"); | ||
1067 | pBSSEntry->extra_ie = 1; | ||
1068 | break; | ||
1069 | |||
1070 | case FH_PARAM_SET: | ||
1071 | pFH = (struct ieeetypes_fhparamset *) pcurrentptr; | ||
1072 | memmove(&pBSSEntry->phyparamset.fhparamset, pFH, | ||
1073 | sizeof(struct ieeetypes_fhparamset)); | ||
1074 | pBSSEntry->phyparamset.fhparamset.dwelltime | ||
1075 | = | ||
1076 | le16_to_cpu(pBSSEntry->phyparamset.fhparamset. | ||
1077 | dwelltime); | ||
1078 | break; | ||
1079 | |||
1080 | case DS_PARAM_SET: | ||
1081 | pDS = (struct ieeetypes_dsparamset *) pcurrentptr; | ||
1082 | |||
1083 | pBSSEntry->channel = pDS->currentchan; | ||
1084 | |||
1085 | memcpy(&pBSSEntry->phyparamset.dsparamset, pDS, | ||
1086 | sizeof(struct ieeetypes_dsparamset)); | ||
1087 | break; | ||
1088 | |||
1089 | case CF_PARAM_SET: | ||
1090 | pCF = (struct ieeetypes_cfparamset *) pcurrentptr; | ||
1091 | |||
1092 | memcpy(&pBSSEntry->ssparamset.cfparamset, pCF, | ||
1093 | sizeof(struct ieeetypes_cfparamset)); | ||
1094 | break; | ||
1095 | |||
1096 | case IBSS_PARAM_SET: | ||
1097 | pibss = (struct ieeetypes_ibssparamset *) pcurrentptr; | ||
1098 | pBSSEntry->atimwindow = | ||
1099 | le32_to_cpu(pibss->atimwindow); | ||
1100 | |||
1101 | memmove(&pBSSEntry->ssparamset.ibssparamset, pibss, | ||
1102 | sizeof(struct ieeetypes_ibssparamset)); | ||
1103 | |||
1104 | pBSSEntry->ssparamset.ibssparamset.atimwindow | ||
1105 | = | ||
1106 | le16_to_cpu(pBSSEntry->ssparamset.ibssparamset. | ||
1107 | atimwindow); | ||
1108 | break; | ||
1109 | |||
1110 | /* Handle Country Info IE */ | ||
1111 | case COUNTRY_INFO: | ||
1112 | pcountryinfo = | ||
1113 | (struct ieeetypes_countryinfoset *) pcurrentptr; | ||
1114 | |||
1115 | if (pcountryinfo->len < | ||
1116 | sizeof(pcountryinfo->countrycode) | ||
1117 | || pcountryinfo->len > 254) { | ||
1118 | lbs_pr_debug(1, "InterpretIE: 11D- Err " | ||
1119 | "CountryInfo len =%d min=%d max=254\n", | ||
1120 | pcountryinfo->len, | ||
1121 | sizeof(pcountryinfo->countrycode)); | ||
1122 | LEAVE(); | ||
1123 | return -1; | ||
1124 | } | ||
1125 | |||
1126 | memcpy(&pBSSEntry->countryinfo, | ||
1127 | pcountryinfo, pcountryinfo->len + 2); | ||
1128 | lbs_dbg_hex("InterpretIE: 11D- CountryInfo:", | ||
1129 | (u8 *) pcountryinfo, | ||
1130 | (u32) (pcountryinfo->len + 2)); | ||
1131 | break; | ||
1132 | |||
1133 | case EXTENDED_SUPPORTED_RATES: | ||
1134 | /* | ||
1135 | * only process extended supported rate | ||
1136 | * if data rate is already found. | ||
1137 | * data rate IE should come before | ||
1138 | * extended supported rate IE | ||
1139 | */ | ||
1140 | if (founddatarateie) { | ||
1141 | if ((elemlen + ratesize) > WLAN_SUPPORTED_RATES) { | ||
1142 | bytestocopy = | ||
1143 | (WLAN_SUPPORTED_RATES - ratesize); | ||
1144 | } else { | ||
1145 | bytestocopy = elemlen; | ||
1146 | } | ||
1147 | |||
1148 | pRate = (u8 *) pBSSEntry->datarates; | ||
1149 | pRate += ratesize; | ||
1150 | memmove(pRate, (pcurrentptr + 2), bytestocopy); | ||
1151 | |||
1152 | pRate = (u8 *) pBSSEntry->libertas_supported_rates; | ||
1153 | |||
1154 | pRate += ratesize; | ||
1155 | memmove(pRate, (pcurrentptr + 2), bytestocopy); | ||
1156 | } | ||
1157 | break; | ||
1158 | |||
1159 | case VENDOR_SPECIFIC_221: | ||
1160 | #define IE_ID_LEN_FIELDS_BYTES 2 | ||
1161 | pIe = (struct IE_WPA *)pcurrentptr; | ||
1162 | |||
1163 | if (!memcmp(pIe->oui, oui01, sizeof(oui01))) { | ||
1164 | pwpa_supplicant->wpa_ie_len | ||
1165 | = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES, | ||
1166 | sizeof(pwpa_supplicant->wpa_ie)); | ||
1167 | memcpy(pwpa_supplicant->wpa_ie, | ||
1168 | pcurrentptr, | ||
1169 | pwpa_supplicant->wpa_ie_len); | ||
1170 | lbs_dbg_hex("InterpretIE: Resp WPA_IE", | ||
1171 | pwpa_supplicant->wpa_ie, elemlen); | ||
1172 | } | ||
1173 | break; | ||
1174 | case WPA2_IE: | ||
1175 | pIe = (struct IE_WPA *)pcurrentptr; | ||
1176 | pwpa2_supplicant->wpa_ie_len | ||
1177 | = min_t(size_t, elemlen + IE_ID_LEN_FIELDS_BYTES, | ||
1178 | sizeof(pwpa2_supplicant->wpa_ie)); | ||
1179 | memcpy(pwpa2_supplicant->wpa_ie, | ||
1180 | pcurrentptr, pwpa2_supplicant->wpa_ie_len); | ||
1181 | |||
1182 | lbs_dbg_hex("InterpretIE: Resp WPA2_IE", | ||
1183 | pwpa2_supplicant->wpa_ie, elemlen); | ||
1184 | break; | ||
1185 | case TIM: | ||
1186 | break; | ||
1187 | |||
1188 | case CHALLENGE_TEXT: | ||
1189 | break; | ||
1190 | } | ||
1191 | |||
1192 | pcurrentptr += elemlen + 2; | ||
1193 | |||
1194 | /* need to account for IE ID and IE len */ | ||
1195 | bytesleftforcurrentbeacon -= (elemlen + 2); | ||
1196 | |||
1197 | } /* while (bytesleftforcurrentbeacon > 2) */ | ||
1198 | |||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | /** | ||
1203 | * @brief Compare two SSIDs | ||
1204 | * | ||
1205 | * @param ssid1 A pointer to ssid to compare | ||
1206 | * @param ssid2 A pointer to ssid to compare | ||
1207 | * | ||
1208 | * @return 0--ssid is same, otherwise is different | ||
1209 | */ | ||
1210 | int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, struct WLAN_802_11_SSID *ssid2) | ||
1211 | { | ||
1212 | if (!ssid1 || !ssid2) | ||
1213 | return -1; | ||
1214 | |||
1215 | if (ssid1->ssidlength != ssid2->ssidlength) | ||
1216 | return -1; | ||
1217 | |||
1218 | return memcmp(ssid1->ssid, ssid2->ssid, ssid1->ssidlength); | ||
1219 | } | ||
1220 | |||
1221 | /** | ||
1222 | * @brief This function finds a specific compatible BSSID in the scan list | ||
1223 | * | ||
1224 | * @param adapter A pointer to wlan_adapter | ||
1225 | * @param bssid BSSID to find in the scan list | ||
1226 | * @param mode Network mode: Infrastructure or IBSS | ||
1227 | * | ||
1228 | * @return index in BSSID list, or error return code (< 0) | ||
1229 | */ | ||
1230 | int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode) | ||
1231 | { | ||
1232 | int ret = -ENETUNREACH; | ||
1233 | int i; | ||
1234 | |||
1235 | if (!bssid) | ||
1236 | return -EFAULT; | ||
1237 | |||
1238 | lbs_pr_debug(1, "FindBSSID: Num of BSSIDs = %d\n", | ||
1239 | adapter->numinscantable); | ||
1240 | |||
1241 | /* Look through the scan table for a compatible match. The ret return | ||
1242 | * variable will be equal to the index in the scan table (greater | ||
1243 | * than zero) if the network is compatible. The loop will continue | ||
1244 | * past a matched bssid that is not compatible in case there is an | ||
1245 | * AP with multiple SSIDs assigned to the same BSSID | ||
1246 | */ | ||
1247 | for (i = 0; ret < 0 && i < adapter->numinscantable; i++) { | ||
1248 | if (!memcmp(adapter->scantable[i].macaddress, bssid, ETH_ALEN)) { | ||
1249 | switch (mode) { | ||
1250 | case wlan802_11infrastructure: | ||
1251 | case wlan802_11ibss: | ||
1252 | ret = is_network_compatible(adapter, i, mode); | ||
1253 | break; | ||
1254 | default: | ||
1255 | ret = i; | ||
1256 | break; | ||
1257 | } | ||
1258 | } | ||
1259 | } | ||
1260 | |||
1261 | return ret; | ||
1262 | } | ||
1263 | |||
1264 | /** | ||
1265 | * @brief This function finds ssid in ssid list. | ||
1266 | * | ||
1267 | * @param adapter A pointer to wlan_adapter | ||
1268 | * @param ssid SSID to find in the list | ||
1269 | * @param bssid BSSID to qualify the SSID selection (if provided) | ||
1270 | * @param mode Network mode: Infrastructure or IBSS | ||
1271 | * | ||
1272 | * @return index in BSSID list | ||
1273 | */ | ||
1274 | int libertas_find_SSID_in_list(wlan_adapter * adapter, | ||
1275 | struct WLAN_802_11_SSID *ssid, u8 * bssid, int mode) | ||
1276 | { | ||
1277 | int net = -ENETUNREACH; | ||
1278 | u8 bestrssi = 0; | ||
1279 | int i; | ||
1280 | int j; | ||
1281 | |||
1282 | lbs_pr_debug(1, "Num of Entries in Table = %d\n", adapter->numinscantable); | ||
1283 | |||
1284 | for (i = 0; i < adapter->numinscantable; i++) { | ||
1285 | if (!libertas_SSID_cmp(&adapter->scantable[i].ssid, ssid) && | ||
1286 | (!bssid || | ||
1287 | !memcmp(adapter->scantable[i]. | ||
1288 | macaddress, bssid, ETH_ALEN))) { | ||
1289 | switch (mode) { | ||
1290 | case wlan802_11infrastructure: | ||
1291 | case wlan802_11ibss: | ||
1292 | j = is_network_compatible(adapter, i, mode); | ||
1293 | |||
1294 | if (j >= 0) { | ||
1295 | if (bssid) { | ||
1296 | return i; | ||
1297 | } | ||
1298 | |||
1299 | if (SCAN_RSSI | ||
1300 | (adapter->scantable[i].rssi) | ||
1301 | > bestrssi) { | ||
1302 | bestrssi = | ||
1303 | SCAN_RSSI(adapter-> | ||
1304 | scantable[i]. | ||
1305 | rssi); | ||
1306 | net = i; | ||
1307 | } | ||
1308 | } else { | ||
1309 | if (net == -ENETUNREACH) { | ||
1310 | net = j; | ||
1311 | } | ||
1312 | } | ||
1313 | break; | ||
1314 | case wlan802_11autounknown: | ||
1315 | default: | ||
1316 | if (SCAN_RSSI(adapter->scantable[i].rssi) | ||
1317 | > bestrssi) { | ||
1318 | bestrssi = | ||
1319 | SCAN_RSSI(adapter->scantable[i]. | ||
1320 | rssi); | ||
1321 | net = i; | ||
1322 | } | ||
1323 | break; | ||
1324 | } | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | return net; | ||
1329 | } | ||
1330 | |||
1331 | /** | ||
1332 | * @brief This function finds the best SSID in the Scan List | ||
1333 | * | ||
1334 | * Search the scan table for the best SSID that also matches the current | ||
1335 | * adapter network preference (infrastructure or adhoc) | ||
1336 | * | ||
1337 | * @param adapter A pointer to wlan_adapter | ||
1338 | * | ||
1339 | * @return index in BSSID list | ||
1340 | */ | ||
1341 | int libertas_find_best_SSID_in_list(wlan_adapter * adapter, | ||
1342 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode) | ||
1343 | { | ||
1344 | int bestnet = -ENETUNREACH; | ||
1345 | u8 bestrssi = 0; | ||
1346 | int i; | ||
1347 | |||
1348 | ENTER(); | ||
1349 | |||
1350 | lbs_pr_debug(1, "Num of BSSIDs = %d\n", adapter->numinscantable); | ||
1351 | |||
1352 | for (i = 0; i < adapter->numinscantable; i++) { | ||
1353 | switch (mode) { | ||
1354 | case wlan802_11infrastructure: | ||
1355 | case wlan802_11ibss: | ||
1356 | if (is_network_compatible(adapter, i, mode) >= 0) { | ||
1357 | if (SCAN_RSSI(adapter->scantable[i].rssi) > | ||
1358 | bestrssi) { | ||
1359 | bestrssi = | ||
1360 | SCAN_RSSI(adapter->scantable[i]. | ||
1361 | rssi); | ||
1362 | bestnet = i; | ||
1363 | } | ||
1364 | } | ||
1365 | break; | ||
1366 | case wlan802_11autounknown: | ||
1367 | default: | ||
1368 | if (SCAN_RSSI(adapter->scantable[i].rssi) > bestrssi) { | ||
1369 | bestrssi = | ||
1370 | SCAN_RSSI(adapter->scantable[i].rssi); | ||
1371 | bestnet = i; | ||
1372 | } | ||
1373 | break; | ||
1374 | } | ||
1375 | } | ||
1376 | |||
1377 | LEAVE(); | ||
1378 | return bestnet; | ||
1379 | } | ||
1380 | |||
1381 | /** | ||
1382 | * @brief Find the AP with specific ssid in the scan list | ||
1383 | * | ||
1384 | * @param priv A pointer to wlan_private structure | ||
1385 | * @param pSSID A pointer to AP's ssid | ||
1386 | * | ||
1387 | * @return 0--success, otherwise--fail | ||
1388 | */ | ||
1389 | int libertas_find_best_network_SSID(wlan_private * priv, | ||
1390 | struct WLAN_802_11_SSID *pSSID, | ||
1391 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode, | ||
1392 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode) | ||
1393 | { | ||
1394 | wlan_adapter *adapter = priv->adapter; | ||
1395 | int ret = 0; | ||
1396 | struct bss_descriptor *preqbssid; | ||
1397 | int i; | ||
1398 | |||
1399 | ENTER(); | ||
1400 | |||
1401 | memset(pSSID, 0, sizeof(struct WLAN_802_11_SSID)); | ||
1402 | |||
1403 | wlan_scan_networks(priv, NULL); | ||
1404 | if (adapter->surpriseremoved) | ||
1405 | return -1; | ||
1406 | wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); | ||
1407 | |||
1408 | i = libertas_find_best_SSID_in_list(adapter, preferred_mode); | ||
1409 | if (i < 0) { | ||
1410 | ret = -1; | ||
1411 | goto out; | ||
1412 | } | ||
1413 | |||
1414 | preqbssid = &adapter->scantable[i]; | ||
1415 | memcpy(pSSID, &preqbssid->ssid, | ||
1416 | sizeof(struct WLAN_802_11_SSID)); | ||
1417 | *out_mode = preqbssid->inframode; | ||
1418 | |||
1419 | if (!pSSID->ssidlength) { | ||
1420 | ret = -1; | ||
1421 | } | ||
1422 | |||
1423 | out: | ||
1424 | LEAVE(); | ||
1425 | return ret; | ||
1426 | } | ||
1427 | |||
1428 | /** | ||
1429 | * @brief Scan Network | ||
1430 | * | ||
1431 | * @param dev A pointer to net_device structure | ||
1432 | * @param info A pointer to iw_request_info structure | ||
1433 | * @param vwrq A pointer to iw_param structure | ||
1434 | * @param extra A pointer to extra data buf | ||
1435 | * | ||
1436 | * @return 0 --success, otherwise fail | ||
1437 | */ | ||
1438 | int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, | ||
1439 | struct iw_param *vwrq, char *extra) | ||
1440 | { | ||
1441 | wlan_private *priv = dev->priv; | ||
1442 | wlan_adapter *adapter = priv->adapter; | ||
1443 | union iwreq_data wrqu; | ||
1444 | |||
1445 | ENTER(); | ||
1446 | |||
1447 | if (!wlan_scan_networks(priv, NULL)) { | ||
1448 | memset(&wrqu, 0, sizeof(union iwreq_data)); | ||
1449 | wireless_send_event(priv->wlan_dev.netdev, SIOCGIWSCAN, &wrqu, | ||
1450 | NULL); | ||
1451 | } | ||
1452 | |||
1453 | if (adapter->surpriseremoved) | ||
1454 | return -1; | ||
1455 | |||
1456 | LEAVE(); | ||
1457 | return 0; | ||
1458 | } | ||
1459 | |||
1460 | /** | ||
1461 | * @brief Send a scan command for all available channels filtered on a spec | ||
1462 | * | ||
1463 | * @param priv A pointer to wlan_private structure | ||
1464 | * @param prequestedssid A pointer to AP's ssid | ||
1465 | * @param keeppreviousscan Flag used to save/clear scan table before scan | ||
1466 | * | ||
1467 | * @return 0-success, otherwise fail | ||
1468 | */ | ||
1469 | int libertas_send_specific_SSID_scan(wlan_private * priv, | ||
1470 | struct WLAN_802_11_SSID *prequestedssid, | ||
1471 | u8 keeppreviousscan) | ||
1472 | { | ||
1473 | wlan_adapter *adapter = priv->adapter; | ||
1474 | struct wlan_ioctl_user_scan_cfg scancfg; | ||
1475 | |||
1476 | ENTER(); | ||
1477 | |||
1478 | if (prequestedssid == NULL) { | ||
1479 | return -1; | ||
1480 | } | ||
1481 | |||
1482 | memset(&scancfg, 0x00, sizeof(scancfg)); | ||
1483 | |||
1484 | memcpy(scancfg.specificSSID, prequestedssid->ssid, | ||
1485 | prequestedssid->ssidlength); | ||
1486 | scancfg.keeppreviousscan = keeppreviousscan; | ||
1487 | |||
1488 | wlan_scan_networks(priv, &scancfg); | ||
1489 | if (adapter->surpriseremoved) | ||
1490 | return -1; | ||
1491 | wait_event_interruptible(adapter->cmd_pending, !adapter->nr_cmd_pending); | ||
1492 | |||
1493 | LEAVE(); | ||
1494 | return 0; | ||
1495 | } | ||
1496 | |||
1497 | /** | ||
1498 | * @brief scan an AP with specific BSSID | ||
1499 | * | ||
1500 | * @param priv A pointer to wlan_private structure | ||
1501 | * @param bssid A pointer to AP's bssid | ||
1502 | * @param keeppreviousscan Flag used to save/clear scan table before scan | ||
1503 | * | ||
1504 | * @return 0-success, otherwise fail | ||
1505 | */ | ||
1506 | int libertas_send_specific_BSSID_scan(wlan_private * priv, u8 * bssid, u8 keeppreviousscan) | ||
1507 | { | ||
1508 | struct wlan_ioctl_user_scan_cfg scancfg; | ||
1509 | |||
1510 | ENTER(); | ||
1511 | |||
1512 | if (bssid == NULL) { | ||
1513 | return -1; | ||
1514 | } | ||
1515 | |||
1516 | memset(&scancfg, 0x00, sizeof(scancfg)); | ||
1517 | memcpy(scancfg.specificBSSID, bssid, sizeof(scancfg.specificBSSID)); | ||
1518 | scancfg.keeppreviousscan = keeppreviousscan; | ||
1519 | |||
1520 | wlan_scan_networks(priv, &scancfg); | ||
1521 | if (priv->adapter->surpriseremoved) | ||
1522 | return -1; | ||
1523 | wait_event_interruptible(priv->adapter->cmd_pending, | ||
1524 | !priv->adapter->nr_cmd_pending); | ||
1525 | |||
1526 | LEAVE(); | ||
1527 | return 0; | ||
1528 | } | ||
1529 | |||
1530 | /** | ||
1531 | * @brief Retrieve the scan table entries via wireless tools IOCTL call | ||
1532 | * | ||
1533 | * @param dev A pointer to net_device structure | ||
1534 | * @param info A pointer to iw_request_info structure | ||
1535 | * @param dwrq A pointer to iw_point structure | ||
1536 | * @param extra A pointer to extra data buf | ||
1537 | * | ||
1538 | * @return 0 --success, otherwise fail | ||
1539 | */ | ||
1540 | int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, | ||
1541 | struct iw_point *dwrq, char *extra) | ||
1542 | { | ||
1543 | wlan_private *priv = dev->priv; | ||
1544 | wlan_adapter *adapter = priv->adapter; | ||
1545 | int ret = 0; | ||
1546 | char *current_ev = extra; | ||
1547 | char *end_buf = extra + IW_SCAN_MAX_DATA; | ||
1548 | struct chan_freq_power *cfp; | ||
1549 | struct bss_descriptor *pscantable; | ||
1550 | char *current_val; /* For rates */ | ||
1551 | struct iw_event iwe; /* Temporary buffer */ | ||
1552 | int i; | ||
1553 | int j; | ||
1554 | int rate; | ||
1555 | #define PERFECT_RSSI ((u8)50) | ||
1556 | #define WORST_RSSI ((u8)0) | ||
1557 | #define RSSI_DIFF ((u8)(PERFECT_RSSI - WORST_RSSI)) | ||
1558 | u8 rssi; | ||
1559 | |||
1560 | u8 buf[16 + 256 * 2]; | ||
1561 | u8 *ptr; | ||
1562 | |||
1563 | ENTER(); | ||
1564 | |||
1565 | /* | ||
1566 | * if there's either commands in the queue or one being | ||
1567 | * processed return -EAGAIN for iwlist to retry later. | ||
1568 | */ | ||
1569 | if (adapter->nr_cmd_pending) | ||
1570 | return -EAGAIN; | ||
1571 | |||
1572 | if (adapter->connect_status == libertas_connected) | ||
1573 | lbs_pr_debug(1, "Current ssid: %32s\n", | ||
1574 | adapter->curbssparams.ssid.ssid); | ||
1575 | |||
1576 | lbs_pr_debug(1, "Scan: Get: numinscantable = %d\n", | ||
1577 | adapter->numinscantable); | ||
1578 | |||
1579 | /* The old API using SIOCGIWAPLIST had a hard limit of IW_MAX_AP. | ||
1580 | * The new API using SIOCGIWSCAN is only limited by buffer size | ||
1581 | * WE-14 -> WE-16 the buffer is limited to IW_SCAN_MAX_DATA bytes | ||
1582 | * which is 4096. | ||
1583 | */ | ||
1584 | for (i = 0; i < adapter->numinscantable; i++) { | ||
1585 | if ((current_ev + MAX_SCAN_CELL_SIZE) >= end_buf) { | ||
1586 | lbs_pr_debug(1, "i=%d break out: current_ev=%p end_buf=%p " | ||
1587 | "MAX_SCAN_CELL_SIZE=%d\n", | ||
1588 | i, current_ev, end_buf, MAX_SCAN_CELL_SIZE); | ||
1589 | break; | ||
1590 | } | ||
1591 | |||
1592 | pscantable = &adapter->scantable[i]; | ||
1593 | |||
1594 | lbs_pr_debug(1, "i=%d ssid: %32s\n", i, pscantable->ssid.ssid); | ||
1595 | |||
1596 | cfp = | ||
1597 | libertas_find_cfp_by_band_and_channel(adapter, 0, | ||
1598 | pscantable->channel); | ||
1599 | if (!cfp) { | ||
1600 | lbs_pr_debug(1, "Invalid channel number %d\n", | ||
1601 | pscantable->channel); | ||
1602 | continue; | ||
1603 | } | ||
1604 | |||
1605 | if (!ssid_valid(&adapter->scantable[i].ssid)) { | ||
1606 | continue; | ||
1607 | } | ||
1608 | |||
1609 | /* First entry *MUST* be the AP MAC address */ | ||
1610 | iwe.cmd = SIOCGIWAP; | ||
1611 | iwe.u.ap_addr.sa_family = ARPHRD_ETHER; | ||
1612 | memcpy(iwe.u.ap_addr.sa_data, | ||
1613 | &adapter->scantable[i].macaddress, ETH_ALEN); | ||
1614 | |||
1615 | iwe.len = IW_EV_ADDR_LEN; | ||
1616 | current_ev = | ||
1617 | iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); | ||
1618 | |||
1619 | //Add the ESSID | ||
1620 | iwe.u.data.length = adapter->scantable[i].ssid.ssidlength; | ||
1621 | |||
1622 | if (iwe.u.data.length > 32) { | ||
1623 | iwe.u.data.length = 32; | ||
1624 | } | ||
1625 | |||
1626 | iwe.cmd = SIOCGIWESSID; | ||
1627 | iwe.u.data.flags = 1; | ||
1628 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1629 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1630 | adapter->scantable[i].ssid. | ||
1631 | ssid); | ||
1632 | |||
1633 | //Add mode | ||
1634 | iwe.cmd = SIOCGIWMODE; | ||
1635 | iwe.u.mode = adapter->scantable[i].inframode + 1; | ||
1636 | iwe.len = IW_EV_UINT_LEN; | ||
1637 | current_ev = | ||
1638 | iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); | ||
1639 | |||
1640 | //frequency | ||
1641 | iwe.cmd = SIOCGIWFREQ; | ||
1642 | iwe.u.freq.m = (long)cfp->freq * 100000; | ||
1643 | iwe.u.freq.e = 1; | ||
1644 | iwe.len = IW_EV_FREQ_LEN; | ||
1645 | current_ev = | ||
1646 | iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); | ||
1647 | |||
1648 | /* Add quality statistics */ | ||
1649 | iwe.cmd = IWEVQUAL; | ||
1650 | iwe.u.qual.updated = IW_QUAL_ALL_UPDATED; | ||
1651 | iwe.u.qual.level = SCAN_RSSI(adapter->scantable[i].rssi); | ||
1652 | |||
1653 | rssi = iwe.u.qual.level - MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
1654 | iwe.u.qual.qual = | ||
1655 | (100 * RSSI_DIFF * RSSI_DIFF - (PERFECT_RSSI - rssi) * | ||
1656 | (15 * (RSSI_DIFF) + 62 * (PERFECT_RSSI - rssi))) / | ||
1657 | (RSSI_DIFF * RSSI_DIFF); | ||
1658 | if (iwe.u.qual.qual > 100) | ||
1659 | iwe.u.qual.qual = 100; | ||
1660 | else if (iwe.u.qual.qual < 1) | ||
1661 | iwe.u.qual.qual = 0; | ||
1662 | |||
1663 | if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { | ||
1664 | iwe.u.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
1665 | } else { | ||
1666 | iwe.u.qual.noise = | ||
1667 | CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
1668 | } | ||
1669 | if ((adapter->inframode == wlan802_11ibss) && | ||
1670 | !libertas_SSID_cmp(&adapter->curbssparams.ssid, | ||
1671 | &adapter->scantable[i].ssid) | ||
1672 | && adapter->adhoccreate) { | ||
1673 | ret = libertas_prepare_and_send_command(priv, | ||
1674 | cmd_802_11_rssi, | ||
1675 | 0, | ||
1676 | cmd_option_waitforrsp, | ||
1677 | 0, NULL); | ||
1678 | |||
1679 | if (!ret) { | ||
1680 | iwe.u.qual.level = | ||
1681 | CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / | ||
1682 | AVG_SCALE, | ||
1683 | adapter->NF[TYPE_RXPD][TYPE_AVG] / | ||
1684 | AVG_SCALE); | ||
1685 | } | ||
1686 | } | ||
1687 | iwe.len = IW_EV_QUAL_LEN; | ||
1688 | current_ev = | ||
1689 | iwe_stream_add_event(current_ev, end_buf, &iwe, iwe.len); | ||
1690 | |||
1691 | /* Add encryption capability */ | ||
1692 | iwe.cmd = SIOCGIWENCODE; | ||
1693 | if (adapter->scantable[i].privacy) { | ||
1694 | iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; | ||
1695 | } else { | ||
1696 | iwe.u.data.flags = IW_ENCODE_DISABLED; | ||
1697 | } | ||
1698 | iwe.u.data.length = 0; | ||
1699 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1700 | current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1701 | adapter->scantable->ssid. | ||
1702 | ssid); | ||
1703 | |||
1704 | current_val = current_ev + IW_EV_LCP_LEN; | ||
1705 | |||
1706 | iwe.cmd = SIOCGIWRATE; | ||
1707 | |||
1708 | iwe.u.bitrate.fixed = 0; | ||
1709 | iwe.u.bitrate.disabled = 0; | ||
1710 | iwe.u.bitrate.value = 0; | ||
1711 | |||
1712 | /* Bit rate given in 500 kb/s units (+ 0x80) */ | ||
1713 | for (j = 0; j < sizeof(adapter->scantable[i].libertas_supported_rates); | ||
1714 | j++) { | ||
1715 | if (adapter->scantable[i].libertas_supported_rates[j] == 0) { | ||
1716 | break; | ||
1717 | } | ||
1718 | rate = | ||
1719 | (adapter->scantable[i].libertas_supported_rates[j] & 0x7F) * | ||
1720 | 500000; | ||
1721 | if (rate > iwe.u.bitrate.value) { | ||
1722 | iwe.u.bitrate.value = rate; | ||
1723 | } | ||
1724 | |||
1725 | iwe.u.bitrate.value = | ||
1726 | (adapter->scantable[i].libertas_supported_rates[j] | ||
1727 | & 0x7f) * 500000; | ||
1728 | iwe.len = IW_EV_PARAM_LEN; | ||
1729 | current_ev = | ||
1730 | iwe_stream_add_value(current_ev, current_val, | ||
1731 | end_buf, &iwe, iwe.len); | ||
1732 | |||
1733 | } | ||
1734 | if ((adapter->scantable[i].inframode == wlan802_11ibss) | ||
1735 | && !libertas_SSID_cmp(&adapter->curbssparams.ssid, | ||
1736 | &adapter->scantable[i].ssid) | ||
1737 | && adapter->adhoccreate) { | ||
1738 | iwe.u.bitrate.value = 22 * 500000; | ||
1739 | } | ||
1740 | iwe.len = IW_EV_PARAM_LEN; | ||
1741 | current_ev = | ||
1742 | iwe_stream_add_value(current_ev, current_val, end_buf, &iwe, | ||
1743 | iwe.len); | ||
1744 | |||
1745 | /* Add new value to event */ | ||
1746 | current_val = current_ev + IW_EV_LCP_LEN; | ||
1747 | |||
1748 | if (adapter->scantable[i].wpa2_supplicant.wpa_ie[0] == WPA2_IE) { | ||
1749 | memset(&iwe, 0, sizeof(iwe)); | ||
1750 | memset(buf, 0, sizeof(buf)); | ||
1751 | memcpy(buf, adapter->scantable[i]. | ||
1752 | wpa2_supplicant.wpa_ie, | ||
1753 | adapter->scantable[i].wpa2_supplicant. | ||
1754 | wpa_ie_len); | ||
1755 | iwe.cmd = IWEVGENIE; | ||
1756 | iwe.u.data.length = adapter->scantable[i]. | ||
1757 | wpa2_supplicant.wpa_ie_len; | ||
1758 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1759 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
1760 | &iwe, buf); | ||
1761 | } | ||
1762 | if (adapter->scantable[i].wpa_supplicant.wpa_ie[0] == WPA_IE) { | ||
1763 | memset(&iwe, 0, sizeof(iwe)); | ||
1764 | memset(buf, 0, sizeof(buf)); | ||
1765 | memcpy(buf, adapter->scantable[i]. | ||
1766 | wpa_supplicant.wpa_ie, | ||
1767 | adapter->scantable[i].wpa_supplicant. | ||
1768 | wpa_ie_len); | ||
1769 | iwe.cmd = IWEVGENIE; | ||
1770 | iwe.u.data.length = adapter->scantable[i]. | ||
1771 | wpa_supplicant.wpa_ie_len; | ||
1772 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1773 | current_ev = iwe_stream_add_point(current_ev, end_buf, | ||
1774 | &iwe, buf); | ||
1775 | } | ||
1776 | |||
1777 | |||
1778 | if (adapter->scantable[i].extra_ie != 0) { | ||
1779 | memset(&iwe, 0, sizeof(iwe)); | ||
1780 | memset(buf, 0, sizeof(buf)); | ||
1781 | ptr = buf; | ||
1782 | ptr += sprintf(ptr, "extra_ie"); | ||
1783 | iwe.u.data.length = strlen(buf); | ||
1784 | |||
1785 | lbs_pr_debug(1, "iwe.u.data.length %d\n", | ||
1786 | iwe.u.data.length); | ||
1787 | lbs_pr_debug(1, "BUF: %s \n", buf); | ||
1788 | |||
1789 | iwe.cmd = IWEVCUSTOM; | ||
1790 | iwe.len = IW_EV_POINT_LEN + iwe.u.data.length; | ||
1791 | current_ev = | ||
1792 | iwe_stream_add_point(current_ev, end_buf, &iwe, | ||
1793 | buf); | ||
1794 | } | ||
1795 | |||
1796 | current_val = current_ev + IW_EV_LCP_LEN; | ||
1797 | |||
1798 | /* | ||
1799 | * Check if we added any event | ||
1800 | */ | ||
1801 | if ((current_val - current_ev) > IW_EV_LCP_LEN) | ||
1802 | current_ev = current_val; | ||
1803 | } | ||
1804 | |||
1805 | dwrq->length = (current_ev - extra); | ||
1806 | dwrq->flags = 0; | ||
1807 | |||
1808 | LEAVE(); | ||
1809 | return 0; | ||
1810 | } | ||
1811 | |||
1812 | /** | ||
1813 | * @brief Prepare a scan command to be sent to the firmware | ||
1814 | * | ||
1815 | * Use the wlan_scan_cmd_config sent to the command processing module in | ||
1816 | * the libertas_prepare_and_send_command to configure a cmd_ds_802_11_scan command | ||
1817 | * struct to send to firmware. | ||
1818 | * | ||
1819 | * The fixed fields specifying the BSS type and BSSID filters as well as a | ||
1820 | * variable number/length of TLVs are sent in the command to firmware. | ||
1821 | * | ||
1822 | * @param priv A pointer to wlan_private structure | ||
1823 | * @param cmd A pointer to cmd_ds_command structure to be sent to | ||
1824 | * firmware with the cmd_DS_801_11_SCAN structure | ||
1825 | * @param pdata_buf Void pointer cast of a wlan_scan_cmd_config struct used | ||
1826 | * to set the fields/TLVs for the command sent to firmware | ||
1827 | * | ||
1828 | * @return 0 or -1 | ||
1829 | * | ||
1830 | * @sa wlan_scan_create_channel_list | ||
1831 | */ | ||
1832 | int libertas_cmd_80211_scan(wlan_private * priv, | ||
1833 | struct cmd_ds_command *cmd, void *pdata_buf) | ||
1834 | { | ||
1835 | struct cmd_ds_802_11_scan *pscan = &cmd->params.scan; | ||
1836 | struct wlan_scan_cmd_config *pscancfg; | ||
1837 | |||
1838 | ENTER(); | ||
1839 | |||
1840 | pscancfg = pdata_buf; | ||
1841 | |||
1842 | /* Set fixed field variables in scan command */ | ||
1843 | pscan->bsstype = pscancfg->bsstype; | ||
1844 | memcpy(pscan->BSSID, pscancfg->specificBSSID, sizeof(pscan->BSSID)); | ||
1845 | memcpy(pscan->tlvbuffer, pscancfg->tlvbuffer, pscancfg->tlvbufferlen); | ||
1846 | |||
1847 | cmd->command = cpu_to_le16(cmd_802_11_scan); | ||
1848 | |||
1849 | /* size is equal to the sizeof(fixed portions) + the TLV len + header */ | ||
1850 | cmd->size = cpu_to_le16(sizeof(pscan->bsstype) | ||
1851 | + sizeof(pscan->BSSID) | ||
1852 | + pscancfg->tlvbufferlen + S_DS_GEN); | ||
1853 | |||
1854 | lbs_pr_debug(1, "SCAN_CMD: command=%x, size=%x, seqnum=%x\n", | ||
1855 | cmd->command, cmd->size, cmd->seqnum); | ||
1856 | LEAVE(); | ||
1857 | return 0; | ||
1858 | } | ||
1859 | |||
1860 | /** | ||
1861 | * @brief This function handles the command response of scan | ||
1862 | * | ||
1863 | * The response buffer for the scan command has the following | ||
1864 | * memory layout: | ||
1865 | * | ||
1866 | * .-----------------------------------------------------------. | ||
1867 | * | header (4 * sizeof(u16)): Standard command response hdr | | ||
1868 | * .-----------------------------------------------------------. | ||
1869 | * | bufsize (u16) : sizeof the BSS Description data | | ||
1870 | * .-----------------------------------------------------------. | ||
1871 | * | NumOfSet (u8) : Number of BSS Descs returned | | ||
1872 | * .-----------------------------------------------------------. | ||
1873 | * | BSSDescription data (variable, size given in bufsize) | | ||
1874 | * .-----------------------------------------------------------. | ||
1875 | * | TLV data (variable, size calculated using header->size, | | ||
1876 | * | bufsize and sizeof the fixed fields above) | | ||
1877 | * .-----------------------------------------------------------. | ||
1878 | * | ||
1879 | * @param priv A pointer to wlan_private structure | ||
1880 | * @param resp A pointer to cmd_ds_command | ||
1881 | * | ||
1882 | * @return 0 or -1 | ||
1883 | */ | ||
1884 | int libertas_ret_80211_scan(wlan_private * priv, struct cmd_ds_command *resp) | ||
1885 | { | ||
1886 | wlan_adapter *adapter = priv->adapter; | ||
1887 | struct cmd_ds_802_11_scan_rsp *pscan; | ||
1888 | struct bss_descriptor newbssentry; | ||
1889 | struct mrvlietypes_data *ptlv; | ||
1890 | struct mrvlietypes_tsftimestamp *ptsftlv; | ||
1891 | u8 *pbssinfo; | ||
1892 | u16 scanrespsize; | ||
1893 | int bytesleft; | ||
1894 | int numintable; | ||
1895 | int bssIdx; | ||
1896 | int idx; | ||
1897 | int tlvbufsize; | ||
1898 | u64 tsfval; | ||
1899 | |||
1900 | ENTER(); | ||
1901 | |||
1902 | pscan = &resp->params.scanresp; | ||
1903 | |||
1904 | if (pscan->nr_sets > MRVDRV_MAX_BSSID_LIST) { | ||
1905 | lbs_pr_debug(1, | ||
1906 | "SCAN_RESP: Invalid number of AP returned (%d)!!\n", | ||
1907 | pscan->nr_sets); | ||
1908 | LEAVE(); | ||
1909 | return -1; | ||
1910 | } | ||
1911 | |||
1912 | bytesleft = le16_to_cpu(pscan->bssdescriptsize); | ||
1913 | lbs_pr_debug(1, "SCAN_RESP: bssdescriptsize %d\n", bytesleft); | ||
1914 | |||
1915 | scanrespsize = le16_to_cpu(resp->size); | ||
1916 | lbs_pr_debug(1, "SCAN_RESP: returned %d AP before parsing\n", | ||
1917 | pscan->nr_sets); | ||
1918 | |||
1919 | numintable = adapter->numinscantable; | ||
1920 | pbssinfo = pscan->bssdesc_and_tlvbuffer; | ||
1921 | |||
1922 | /* The size of the TLV buffer is equal to the entire command response | ||
1923 | * size (scanrespsize) minus the fixed fields (sizeof()'s), the | ||
1924 | * BSS Descriptions (bssdescriptsize as bytesLef) and the command | ||
1925 | * response header (S_DS_GEN) | ||
1926 | */ | ||
1927 | tlvbufsize = scanrespsize - (bytesleft + sizeof(pscan->bssdescriptsize) | ||
1928 | + sizeof(pscan->nr_sets) | ||
1929 | + S_DS_GEN); | ||
1930 | |||
1931 | ptlv = (struct mrvlietypes_data *) (pscan->bssdesc_and_tlvbuffer + bytesleft); | ||
1932 | |||
1933 | /* Search the TLV buffer space in the scan response for any valid TLVs */ | ||
1934 | wlan_ret_802_11_scan_get_tlv_ptrs(ptlv, tlvbufsize, &ptsftlv); | ||
1935 | |||
1936 | /* | ||
1937 | * Process each scan response returned (pscan->nr_sets). Save | ||
1938 | * the information in the newbssentry and then insert into the | ||
1939 | * driver scan table either as an update to an existing entry | ||
1940 | * or as an addition at the end of the table | ||
1941 | */ | ||
1942 | for (idx = 0; idx < pscan->nr_sets && bytesleft; idx++) { | ||
1943 | /* Zero out the newbssentry we are about to store info in */ | ||
1944 | memset(&newbssentry, 0x00, sizeof(newbssentry)); | ||
1945 | |||
1946 | /* Process the data fields and IEs returned for this BSS */ | ||
1947 | if ((InterpretBSSDescriptionWithIE(&newbssentry, | ||
1948 | &pbssinfo, | ||
1949 | &bytesleft) == | ||
1950 | 0) | ||
1951 | && CHECK_SSID_IS_VALID(&newbssentry.ssid)) { | ||
1952 | |||
1953 | lbs_pr_debug(1, | ||
1954 | "SCAN_RESP: BSSID = %02x:%02x:%02x:%02x:%02x:%02x\n", | ||
1955 | newbssentry.macaddress[0], | ||
1956 | newbssentry.macaddress[1], | ||
1957 | newbssentry.macaddress[2], | ||
1958 | newbssentry.macaddress[3], | ||
1959 | newbssentry.macaddress[4], | ||
1960 | newbssentry.macaddress[5]); | ||
1961 | |||
1962 | /* | ||
1963 | * Search the scan table for the same bssid | ||
1964 | */ | ||
1965 | for (bssIdx = 0; bssIdx < numintable; bssIdx++) { | ||
1966 | if (memcmp(newbssentry.macaddress, | ||
1967 | adapter->scantable[bssIdx]. | ||
1968 | macaddress, | ||
1969 | sizeof(newbssentry.macaddress)) == | ||
1970 | 0) { | ||
1971 | /* | ||
1972 | * If the SSID matches as well, it is a duplicate of | ||
1973 | * this entry. Keep the bssIdx set to this | ||
1974 | * entry so we replace the old contents in the table | ||
1975 | */ | ||
1976 | if ((newbssentry.ssid.ssidlength == | ||
1977 | adapter->scantable[bssIdx].ssid. | ||
1978 | ssidlength) | ||
1979 | && | ||
1980 | (memcmp | ||
1981 | (newbssentry.ssid.ssid, | ||
1982 | adapter->scantable[bssIdx].ssid. | ||
1983 | ssid, | ||
1984 | newbssentry.ssid.ssidlength) == | ||
1985 | 0)) { | ||
1986 | lbs_pr_debug(1, | ||
1987 | "SCAN_RESP: Duplicate of index: %d\n", | ||
1988 | bssIdx); | ||
1989 | break; | ||
1990 | } | ||
1991 | } | ||
1992 | } | ||
1993 | /* | ||
1994 | * If the bssIdx is equal to the number of entries in the table, | ||
1995 | * the new entry was not a duplicate; append it to the scan | ||
1996 | * table | ||
1997 | */ | ||
1998 | if (bssIdx == numintable) { | ||
1999 | /* Range check the bssIdx, keep it limited to the last entry */ | ||
2000 | if (bssIdx == MRVDRV_MAX_BSSID_LIST) { | ||
2001 | bssIdx--; | ||
2002 | } else { | ||
2003 | numintable++; | ||
2004 | } | ||
2005 | } | ||
2006 | |||
2007 | /* | ||
2008 | * If the TSF TLV was appended to the scan results, save the | ||
2009 | * this entries TSF value in the networktsf field. The | ||
2010 | * networktsf is the firmware's TSF value at the time the | ||
2011 | * beacon or probe response was received. | ||
2012 | */ | ||
2013 | if (ptsftlv) { | ||
2014 | memcpy(&tsfval, &ptsftlv->tsftable[idx], | ||
2015 | sizeof(tsfval)); | ||
2016 | tsfval = le64_to_cpu(tsfval); | ||
2017 | |||
2018 | memcpy(&newbssentry.networktsf, | ||
2019 | &tsfval, sizeof(newbssentry.networktsf)); | ||
2020 | } | ||
2021 | |||
2022 | /* Copy the locally created newbssentry to the scan table */ | ||
2023 | memcpy(&adapter->scantable[bssIdx], | ||
2024 | &newbssentry, | ||
2025 | sizeof(adapter->scantable[bssIdx])); | ||
2026 | |||
2027 | } else { | ||
2028 | |||
2029 | /* error parsing/interpreting the scan response, skipped */ | ||
2030 | lbs_pr_debug(1, "SCAN_RESP: " | ||
2031 | "InterpretBSSDescriptionWithIE returned ERROR\n"); | ||
2032 | } | ||
2033 | } | ||
2034 | |||
2035 | lbs_pr_debug(1, "SCAN_RESP: Scanned %2d APs, %d valid, %d total\n", | ||
2036 | pscan->nr_sets, numintable - adapter->numinscantable, | ||
2037 | numintable); | ||
2038 | |||
2039 | /* Update the total number of BSSIDs in the scan table */ | ||
2040 | adapter->numinscantable = numintable; | ||
2041 | |||
2042 | LEAVE(); | ||
2043 | return 0; | ||
2044 | } | ||
diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h new file mode 100644 index 000000000000..d93aa7fa44fd --- /dev/null +++ b/drivers/net/wireless/libertas/scan.h | |||
@@ -0,0 +1,216 @@ | |||
1 | /* -*- mode: C; tab-width: 4; indent-tabs-mode: nil -*- */ | ||
2 | /* vi: set expandtab shiftwidth=4 tabstop=4 textwidth=78: */ | ||
3 | |||
4 | /** | ||
5 | * Interface for the wlan network scan routines | ||
6 | * | ||
7 | * Driver interface functions and type declarations for the scan module | ||
8 | * implemented in wlan_scan.c. | ||
9 | */ | ||
10 | #ifndef _WLAN_SCAN_H | ||
11 | #define _WLAN_SCAN_H | ||
12 | |||
13 | #include "hostcmd.h" | ||
14 | |||
15 | /** | ||
16 | * @brief Maximum number of channels that can be sent in a setuserscan ioctl | ||
17 | * | ||
18 | * @sa wlan_ioctl_user_scan_cfg | ||
19 | */ | ||
20 | #define WLAN_IOCTL_USER_SCAN_CHAN_MAX 50 | ||
21 | |||
22 | //! Infrastructure BSS scan type in wlan_scan_cmd_config | ||
23 | #define WLAN_SCAN_BSS_TYPE_BSS 1 | ||
24 | |||
25 | //! Adhoc BSS scan type in wlan_scan_cmd_config | ||
26 | #define WLAN_SCAN_BSS_TYPE_IBSS 2 | ||
27 | |||
28 | //! Adhoc or Infrastructure BSS scan type in wlan_scan_cmd_config, no filter | ||
29 | #define WLAN_SCAN_BSS_TYPE_ANY 3 | ||
30 | |||
31 | /** | ||
32 | * @brief Structure used internally in the wlan driver to configure a scan. | ||
33 | * | ||
34 | * Sent to the command processing module to configure the firmware | ||
35 | * scan command prepared by libertas_cmd_80211_scan. | ||
36 | * | ||
37 | * @sa wlan_scan_networks | ||
38 | * | ||
39 | */ | ||
40 | struct wlan_scan_cmd_config { | ||
41 | /** | ||
42 | * @brief BSS type to be sent in the firmware command | ||
43 | * | ||
44 | * Field can be used to restrict the types of networks returned in the | ||
45 | * scan. valid settings are: | ||
46 | * | ||
47 | * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) | ||
48 | * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) | ||
49 | * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) | ||
50 | */ | ||
51 | u8 bsstype; | ||
52 | |||
53 | /** | ||
54 | * @brief Specific BSSID used to filter scan results in the firmware | ||
55 | */ | ||
56 | u8 specificBSSID[ETH_ALEN]; | ||
57 | |||
58 | /** | ||
59 | * @brief length of TLVs sent in command starting at tlvBuffer | ||
60 | */ | ||
61 | int tlvbufferlen; | ||
62 | |||
63 | /** | ||
64 | * @brief SSID TLV(s) and ChanList TLVs to be sent in the firmware command | ||
65 | * | ||
66 | * @sa TLV_TYPE_CHANLIST, mrvlietypes_chanlistparamset_t | ||
67 | * @sa TLV_TYPE_SSID, mrvlietypes_ssidparamset_t | ||
68 | */ | ||
69 | u8 tlvbuffer[1]; //!< SSID TLV(s) and ChanList TLVs are stored here | ||
70 | }; | ||
71 | |||
72 | /** | ||
73 | * @brief IOCTL channel sub-structure sent in wlan_ioctl_user_scan_cfg | ||
74 | * | ||
75 | * Multiple instances of this structure are included in the IOCTL command | ||
76 | * to configure a instance of a scan on the specific channel. | ||
77 | */ | ||
78 | struct wlan_ioctl_user_scan_chan { | ||
79 | u8 channumber; //!< channel Number to scan | ||
80 | u8 radiotype; //!< Radio type: 'B/G' band = 0, 'A' band = 1 | ||
81 | u8 scantype; //!< Scan type: Active = 0, Passive = 1 | ||
82 | u16 scantime; //!< Scan duration in milliseconds; if 0 default used | ||
83 | }; | ||
84 | |||
85 | /** | ||
86 | * @brief IOCTL input structure to configure an immediate scan cmd to firmware | ||
87 | * | ||
88 | * Used in the setuserscan (WLAN_SET_USER_SCAN) private ioctl. Specifies | ||
89 | * a number of parameters to be used in general for the scan as well | ||
90 | * as a channel list (wlan_ioctl_user_scan_chan) for each scan period | ||
91 | * desired. | ||
92 | * | ||
93 | * @sa libertas_set_user_scan_ioctl | ||
94 | */ | ||
95 | struct wlan_ioctl_user_scan_cfg { | ||
96 | |||
97 | /** | ||
98 | * @brief Flag set to keep the previous scan table intact | ||
99 | * | ||
100 | * If set, the scan results will accumulate, replacing any previous | ||
101 | * matched entries for a BSS with the new scan data | ||
102 | */ | ||
103 | u8 keeppreviousscan; //!< Do not erase the existing scan results | ||
104 | |||
105 | /** | ||
106 | * @brief BSS type to be sent in the firmware command | ||
107 | * | ||
108 | * Field can be used to restrict the types of networks returned in the | ||
109 | * scan. valid settings are: | ||
110 | * | ||
111 | * - WLAN_SCAN_BSS_TYPE_BSS (infrastructure) | ||
112 | * - WLAN_SCAN_BSS_TYPE_IBSS (adhoc) | ||
113 | * - WLAN_SCAN_BSS_TYPE_ANY (unrestricted, adhoc and infrastructure) | ||
114 | */ | ||
115 | u8 bsstype; | ||
116 | |||
117 | /** | ||
118 | * @brief Configure the number of probe requests for active chan scans | ||
119 | */ | ||
120 | u8 numprobes; | ||
121 | |||
122 | /** | ||
123 | * @brief BSSID filter sent in the firmware command to limit the results | ||
124 | */ | ||
125 | u8 specificBSSID[ETH_ALEN]; | ||
126 | |||
127 | /** | ||
128 | * @brief SSID filter sent in the firmware command to limit the results | ||
129 | */ | ||
130 | char specificSSID[IW_ESSID_MAX_SIZE + 1]; | ||
131 | |||
132 | /** | ||
133 | * @brief Variable number (fixed maximum) of channels to scan up | ||
134 | */ | ||
135 | struct wlan_ioctl_user_scan_chan chanlist[WLAN_IOCTL_USER_SCAN_CHAN_MAX]; | ||
136 | }; | ||
137 | |||
138 | /** | ||
139 | * @brief Structure used to store information for each beacon/probe response | ||
140 | */ | ||
141 | struct bss_descriptor { | ||
142 | u8 macaddress[ETH_ALEN]; | ||
143 | |||
144 | struct WLAN_802_11_SSID ssid; | ||
145 | |||
146 | /* WEP encryption requirement */ | ||
147 | u32 privacy; | ||
148 | |||
149 | /* receive signal strength in dBm */ | ||
150 | long rssi; | ||
151 | |||
152 | u32 channel; | ||
153 | |||
154 | u16 beaconperiod; | ||
155 | |||
156 | u32 atimwindow; | ||
157 | |||
158 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE inframode; | ||
159 | u8 libertas_supported_rates[WLAN_SUPPORTED_RATES]; | ||
160 | |||
161 | int extra_ie; | ||
162 | |||
163 | u8 timestamp[8]; //!< TSF value included in the beacon/probe response | ||
164 | union ieeetypes_phyparamset phyparamset; | ||
165 | union IEEEtypes_ssparamset ssparamset; | ||
166 | struct ieeetypes_capinfo cap; | ||
167 | u8 datarates[WLAN_SUPPORTED_RATES]; | ||
168 | |||
169 | __le64 networktsf; //!< TSF timestamp from the current firmware TSF | ||
170 | |||
171 | struct ieeetypes_countryinfofullset countryinfo; | ||
172 | |||
173 | struct WPA_SUPPLICANT wpa_supplicant; | ||
174 | struct WPA_SUPPLICANT wpa2_supplicant; | ||
175 | |||
176 | }; | ||
177 | |||
178 | extern int libertas_SSID_cmp(struct WLAN_802_11_SSID *ssid1, | ||
179 | struct WLAN_802_11_SSID *ssid2); | ||
180 | extern int libertas_find_SSID_in_list(wlan_adapter * adapter, struct WLAN_802_11_SSID *ssid, | ||
181 | u8 * bssid, int mode); | ||
182 | int libertas_find_best_SSID_in_list(wlan_adapter * adapter, enum WLAN_802_11_NETWORK_INFRASTRUCTURE mode); | ||
183 | extern int libertas_find_BSSID_in_list(wlan_adapter * adapter, u8 * bssid, int mode); | ||
184 | |||
185 | int libertas_find_best_network_SSID(wlan_private * priv, | ||
186 | struct WLAN_802_11_SSID *pSSID, | ||
187 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE preferred_mode, | ||
188 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE *out_mode); | ||
189 | |||
190 | extern int libertas_send_specific_SSID_scan(wlan_private * priv, | ||
191 | struct WLAN_802_11_SSID *prequestedssid, | ||
192 | u8 keeppreviousscan); | ||
193 | extern int libertas_send_specific_BSSID_scan(wlan_private * priv, | ||
194 | u8 * bssid, u8 keeppreviousscan); | ||
195 | |||
196 | extern int libertas_cmd_80211_scan(wlan_private * priv, | ||
197 | struct cmd_ds_command *cmd, | ||
198 | void *pdata_buf); | ||
199 | |||
200 | extern int libertas_ret_80211_scan(wlan_private * priv, | ||
201 | struct cmd_ds_command *resp); | ||
202 | |||
203 | int wlan_scan_networks(wlan_private * priv, | ||
204 | const struct wlan_ioctl_user_scan_cfg * puserscanin); | ||
205 | |||
206 | struct ifreq; | ||
207 | |||
208 | struct iw_point; | ||
209 | struct iw_param; | ||
210 | struct iw_request_info; | ||
211 | extern int libertas_get_scan(struct net_device *dev, struct iw_request_info *info, | ||
212 | struct iw_point *dwrq, char *extra); | ||
213 | extern int libertas_set_scan(struct net_device *dev, struct iw_request_info *info, | ||
214 | struct iw_param *vwrq, char *extra); | ||
215 | |||
216 | #endif /* _WLAN_SCAN_H */ | ||
diff --git a/drivers/net/wireless/libertas/thread.h b/drivers/net/wireless/libertas/thread.h new file mode 100644 index 000000000000..207b8a6cc33d --- /dev/null +++ b/drivers/net/wireless/libertas/thread.h | |||
@@ -0,0 +1,52 @@ | |||
1 | #ifndef __WLAN_THREAD_H_ | ||
2 | #define __WLAN_THREAD_H_ | ||
3 | |||
4 | #include <linux/kthread.h> | ||
5 | |||
6 | struct wlan_thread { | ||
7 | struct task_struct *task; | ||
8 | wait_queue_head_t waitq; | ||
9 | pid_t pid; | ||
10 | void *priv; | ||
11 | }; | ||
12 | |||
13 | static inline void wlan_activate_thread(struct wlan_thread * thr) | ||
14 | { | ||
15 | /** Record the thread pid */ | ||
16 | thr->pid = current->pid; | ||
17 | |||
18 | /** Initialize the wait queue */ | ||
19 | init_waitqueue_head(&thr->waitq); | ||
20 | } | ||
21 | |||
22 | static inline void wlan_deactivate_thread(struct wlan_thread * thr) | ||
23 | { | ||
24 | ENTER(); | ||
25 | |||
26 | thr->pid = 0; | ||
27 | |||
28 | LEAVE(); | ||
29 | } | ||
30 | |||
31 | static inline void wlan_create_thread(int (*wlanfunc) (void *), | ||
32 | struct wlan_thread * thr, char *name) | ||
33 | { | ||
34 | thr->task = kthread_run(wlanfunc, thr, "%s", name); | ||
35 | } | ||
36 | |||
37 | static inline int wlan_terminate_thread(struct wlan_thread * thr) | ||
38 | { | ||
39 | ENTER(); | ||
40 | |||
41 | /* Check if the thread is active or not */ | ||
42 | if (!thr->pid) { | ||
43 | printk(KERN_ERR "Thread does not exist\n"); | ||
44 | return -1; | ||
45 | } | ||
46 | kthread_stop(thr->task); | ||
47 | |||
48 | LEAVE(); | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | #endif | ||
diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c new file mode 100644 index 000000000000..82d06223043e --- /dev/null +++ b/drivers/net/wireless/libertas/tx.c | |||
@@ -0,0 +1,285 @@ | |||
1 | /** | ||
2 | * This file contains the handling of TX in wlan driver. | ||
3 | */ | ||
4 | #include <linux/netdevice.h> | ||
5 | |||
6 | #include "hostcmd.h" | ||
7 | #include "radiotap.h" | ||
8 | #include "sbi.h" | ||
9 | #include "decl.h" | ||
10 | #include "defs.h" | ||
11 | #include "dev.h" | ||
12 | #include "wext.h" | ||
13 | |||
14 | /** | ||
15 | * @brief This function converts Tx/Rx rates from IEEE80211_RADIOTAP_RATE | ||
16 | * units (500 Kb/s) into Marvell WLAN format (see Table 8 in Section 3.2.1) | ||
17 | * | ||
18 | * @param rate Input rate | ||
19 | * @return Output Rate (0 if invalid) | ||
20 | */ | ||
21 | static u32 convert_radiotap_rate_to_mv(u8 rate) | ||
22 | { | ||
23 | switch (rate) { | ||
24 | case 2: /* 1 Mbps */ | ||
25 | return 0 | (1 << 4); | ||
26 | case 4: /* 2 Mbps */ | ||
27 | return 1 | (1 << 4); | ||
28 | case 11: /* 5.5 Mbps */ | ||
29 | return 2 | (1 << 4); | ||
30 | case 22: /* 11 Mbps */ | ||
31 | return 3 | (1 << 4); | ||
32 | case 12: /* 6 Mbps */ | ||
33 | return 4 | (1 << 4); | ||
34 | case 18: /* 9 Mbps */ | ||
35 | return 5 | (1 << 4); | ||
36 | case 24: /* 12 Mbps */ | ||
37 | return 6 | (1 << 4); | ||
38 | case 36: /* 18 Mbps */ | ||
39 | return 7 | (1 << 4); | ||
40 | case 48: /* 24 Mbps */ | ||
41 | return 8 | (1 << 4); | ||
42 | case 72: /* 36 Mbps */ | ||
43 | return 9 | (1 << 4); | ||
44 | case 96: /* 48 Mbps */ | ||
45 | return 10 | (1 << 4); | ||
46 | case 108: /* 54 Mbps */ | ||
47 | return 11 | (1 << 4); | ||
48 | } | ||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * @brief This function processes a single packet and sends | ||
54 | * to IF layer | ||
55 | * | ||
56 | * @param priv A pointer to wlan_private structure | ||
57 | * @param skb A pointer to skb which includes TX packet | ||
58 | * @return 0 or -1 | ||
59 | */ | ||
60 | static int SendSinglePacket(wlan_private * priv, struct sk_buff *skb) | ||
61 | { | ||
62 | wlan_adapter *adapter = priv->adapter; | ||
63 | int ret = 0; | ||
64 | struct txpd localtxpd; | ||
65 | struct txpd *plocaltxpd = &localtxpd; | ||
66 | u8 *p802x_hdr; | ||
67 | struct tx_radiotap_hdr *pradiotap_hdr; | ||
68 | u32 new_rate; | ||
69 | u8 *ptr = priv->adapter->tmptxbuf; | ||
70 | |||
71 | ENTER(); | ||
72 | |||
73 | if (priv->adapter->surpriseremoved) | ||
74 | return -1; | ||
75 | |||
76 | if ((priv->adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) | ||
77 | lbs_dbg_hex("TX packet: ", skb->data, | ||
78 | min_t(unsigned int, skb->len, 100)); | ||
79 | |||
80 | if (!skb->len || (skb->len > MRVDRV_ETH_TX_PACKET_BUFFER_SIZE)) { | ||
81 | lbs_pr_debug(1, "Tx error: Bad skb length %d : %d\n", | ||
82 | skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE); | ||
83 | ret = -1; | ||
84 | goto done; | ||
85 | } | ||
86 | |||
87 | memset(plocaltxpd, 0, sizeof(struct txpd)); | ||
88 | |||
89 | plocaltxpd->tx_packet_length = skb->len; | ||
90 | |||
91 | /* offset of actual data */ | ||
92 | plocaltxpd->tx_packet_location = sizeof(struct txpd); | ||
93 | |||
94 | /* TxCtrl set by user or default */ | ||
95 | plocaltxpd->tx_control = adapter->pkttxctrl; | ||
96 | |||
97 | p802x_hdr = skb->data; | ||
98 | if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { | ||
99 | |||
100 | /* locate radiotap header */ | ||
101 | pradiotap_hdr = (struct tx_radiotap_hdr *)skb->data; | ||
102 | |||
103 | /* set txpd fields from the radiotap header */ | ||
104 | new_rate = convert_radiotap_rate_to_mv(pradiotap_hdr->rate); | ||
105 | if (new_rate != 0) { | ||
106 | /* erase tx_control[4:0] */ | ||
107 | plocaltxpd->tx_control &= ~0x1f; | ||
108 | /* write new tx_control[4:0] */ | ||
109 | plocaltxpd->tx_control |= new_rate; | ||
110 | } | ||
111 | |||
112 | /* skip the radiotap header */ | ||
113 | p802x_hdr += sizeof(struct tx_radiotap_hdr); | ||
114 | plocaltxpd->tx_packet_length -= sizeof(struct tx_radiotap_hdr); | ||
115 | |||
116 | } | ||
117 | /* copy destination address from 802.3 or 802.11 header */ | ||
118 | if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) | ||
119 | memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr + 4, ETH_ALEN); | ||
120 | else | ||
121 | memcpy(plocaltxpd->tx_dest_addr_high, p802x_hdr, ETH_ALEN); | ||
122 | |||
123 | lbs_dbg_hex("txpd", (u8 *) plocaltxpd, sizeof(struct txpd)); | ||
124 | |||
125 | if (IS_MESH_FRAME(skb)) { | ||
126 | plocaltxpd->tx_control |= TxPD_MESH_FRAME; | ||
127 | } | ||
128 | |||
129 | memcpy(ptr, plocaltxpd, sizeof(struct txpd)); | ||
130 | |||
131 | ptr += sizeof(struct txpd); | ||
132 | |||
133 | lbs_dbg_hex("Tx Data", (u8 *) p802x_hdr, plocaltxpd->tx_packet_length); | ||
134 | memcpy(ptr, p802x_hdr, plocaltxpd->tx_packet_length); | ||
135 | ret = libertas_sbi_host_to_card(priv, MVMS_DAT, | ||
136 | priv->adapter->tmptxbuf, | ||
137 | plocaltxpd->tx_packet_length + | ||
138 | sizeof(struct txpd)); | ||
139 | |||
140 | if (ret) { | ||
141 | lbs_pr_debug(1, "Tx error: libertas_sbi_host_to_card failed: 0x%X\n", ret); | ||
142 | goto done; | ||
143 | } | ||
144 | |||
145 | lbs_pr_debug(1, "SendSinglePacket succeeds\n"); | ||
146 | |||
147 | done: | ||
148 | if (!ret) { | ||
149 | priv->stats.tx_packets++; | ||
150 | priv->stats.tx_bytes += skb->len; | ||
151 | } else { | ||
152 | priv->stats.tx_dropped++; | ||
153 | priv->stats.tx_errors++; | ||
154 | } | ||
155 | |||
156 | if (!ret && priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) { | ||
157 | /* Keep the skb to echo it back once Tx feedback is | ||
158 | received from FW */ | ||
159 | skb_orphan(skb); | ||
160 | /* stop processing outgoing pkts */ | ||
161 | netif_stop_queue(priv->wlan_dev.netdev); | ||
162 | /* freeze any packets already in our queues */ | ||
163 | priv->adapter->TxLockFlag = 1; | ||
164 | } else { | ||
165 | dev_kfree_skb_any(skb); | ||
166 | priv->adapter->currenttxskb = NULL; | ||
167 | } | ||
168 | |||
169 | LEAVE(); | ||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | |||
174 | void libertas_tx_runqueue(wlan_private *priv) | ||
175 | { | ||
176 | wlan_adapter *adapter = priv->adapter; | ||
177 | int i; | ||
178 | |||
179 | spin_lock(&adapter->txqueue_lock); | ||
180 | for (i = 0; i < adapter->tx_queue_idx; i++) { | ||
181 | struct sk_buff *skb = adapter->tx_queue_ps[i]; | ||
182 | spin_unlock(&adapter->txqueue_lock); | ||
183 | SendSinglePacket(priv, skb); | ||
184 | spin_lock(&adapter->txqueue_lock); | ||
185 | } | ||
186 | adapter->tx_queue_idx = 0; | ||
187 | spin_unlock(&adapter->txqueue_lock); | ||
188 | } | ||
189 | |||
190 | static void wlan_tx_queue(wlan_private *priv, struct sk_buff *skb) | ||
191 | { | ||
192 | wlan_adapter *adapter = priv->adapter; | ||
193 | |||
194 | spin_lock(&adapter->txqueue_lock); | ||
195 | |||
196 | WARN_ON(priv->adapter->tx_queue_idx >= NR_TX_QUEUE); | ||
197 | adapter->tx_queue_ps[adapter->tx_queue_idx++] = skb; | ||
198 | if (adapter->tx_queue_idx == NR_TX_QUEUE) | ||
199 | netif_stop_queue(priv->wlan_dev.netdev); | ||
200 | else | ||
201 | netif_start_queue(priv->wlan_dev.netdev); | ||
202 | |||
203 | spin_unlock(&adapter->txqueue_lock); | ||
204 | } | ||
205 | |||
206 | /** | ||
207 | * @brief This function checks the conditions and sends packet to IF | ||
208 | * layer if everything is ok. | ||
209 | * | ||
210 | * @param priv A pointer to wlan_private structure | ||
211 | * @return n/a | ||
212 | */ | ||
213 | int libertas_process_tx(wlan_private * priv, struct sk_buff *skb) | ||
214 | { | ||
215 | int ret = -1; | ||
216 | |||
217 | ENTER(); | ||
218 | |||
219 | lbs_dbg_hex("TX Data", skb->data, min_t(unsigned int, skb->len, 100)); | ||
220 | |||
221 | if (priv->wlan_dev.dnld_sent) { | ||
222 | lbs_pr_alert( "TX error: dnld_sent = %d, not sending\n", | ||
223 | priv->wlan_dev.dnld_sent); | ||
224 | goto done; | ||
225 | } | ||
226 | |||
227 | if ((priv->adapter->psstate == PS_STATE_SLEEP) || | ||
228 | (priv->adapter->psstate == PS_STATE_PRE_SLEEP)) { | ||
229 | wlan_tx_queue(priv, skb); | ||
230 | return ret; | ||
231 | } | ||
232 | |||
233 | priv->adapter->currenttxskb = skb; | ||
234 | |||
235 | ret = SendSinglePacket(priv, skb); | ||
236 | done: | ||
237 | LEAVE(); | ||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * @brief This function sends to the host the last transmitted packet, | ||
243 | * filling the radiotap headers with transmission information. | ||
244 | * | ||
245 | * @param priv A pointer to wlan_private structure | ||
246 | * @param status A 32 bit value containing transmission status. | ||
247 | * | ||
248 | * @returns void | ||
249 | */ | ||
250 | void libertas_send_tx_feedback(wlan_private * priv) | ||
251 | { | ||
252 | wlan_adapter *adapter = priv->adapter; | ||
253 | struct tx_radiotap_hdr *radiotap_hdr; | ||
254 | u32 status = adapter->eventcause; | ||
255 | int txfail; | ||
256 | int try_count; | ||
257 | |||
258 | if (adapter->radiomode != WLAN_RADIOMODE_RADIOTAP || | ||
259 | adapter->currenttxskb == NULL) | ||
260 | return; | ||
261 | |||
262 | radiotap_hdr = (struct tx_radiotap_hdr *)adapter->currenttxskb->data; | ||
263 | |||
264 | if ((adapter->debugmode & MRVDRV_DEBUG_TX_PATH) != 0) | ||
265 | lbs_dbg_hex("TX feedback: ", (u8 *) radiotap_hdr, | ||
266 | min_t(unsigned int, adapter->currenttxskb->len, 100)); | ||
267 | |||
268 | txfail = (status >> 24); | ||
269 | |||
270 | #if 0 | ||
271 | /* The version of roofnet that we've tested does not use this yet | ||
272 | * But it may be used in the future. | ||
273 | */ | ||
274 | if (txfail) | ||
275 | radiotap_hdr->flags &= IEEE80211_RADIOTAP_F_TX_FAIL; | ||
276 | #endif | ||
277 | try_count = (status >> 16) & 0xff; | ||
278 | radiotap_hdr->data_retries = (try_count) ? | ||
279 | (1 + adapter->txretrycount - try_count) : 0; | ||
280 | libertas_upload_rx_packet(priv, adapter->currenttxskb); | ||
281 | adapter->currenttxskb = NULL; | ||
282 | priv->adapter->TxLockFlag = 0; | ||
283 | if (priv->adapter->connect_status == libertas_connected) | ||
284 | netif_wake_queue(priv->wlan_dev.netdev); | ||
285 | } | ||
diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h new file mode 100644 index 000000000000..09d62f8b1a16 --- /dev/null +++ b/drivers/net/wireless/libertas/types.h | |||
@@ -0,0 +1,289 @@ | |||
1 | /** | ||
2 | * This header file contains definition for global types | ||
3 | */ | ||
4 | #ifndef _WLAN_TYPES_ | ||
5 | #define _WLAN_TYPES_ | ||
6 | |||
7 | #include <linux/if_ether.h> | ||
8 | |||
9 | /** IEEE type definitions */ | ||
10 | enum ieeetypes_elementid { | ||
11 | SSID = 0, | ||
12 | SUPPORTED_RATES, | ||
13 | FH_PARAM_SET, | ||
14 | DS_PARAM_SET, | ||
15 | CF_PARAM_SET, | ||
16 | TIM, | ||
17 | IBSS_PARAM_SET, | ||
18 | COUNTRY_INFO = 7, | ||
19 | |||
20 | CHALLENGE_TEXT = 16, | ||
21 | |||
22 | EXTENDED_SUPPORTED_RATES = 50, | ||
23 | |||
24 | VENDOR_SPECIFIC_221 = 221, | ||
25 | |||
26 | WPA_IE = 221, | ||
27 | WPA2_IE = 48, | ||
28 | |||
29 | EXTRA_IE = 133, | ||
30 | } __attribute__ ((packed)); | ||
31 | |||
32 | #define CAPINFO_MASK (~(0xda00)) | ||
33 | |||
34 | struct ieeetypes_capinfo { | ||
35 | u8 ess:1; | ||
36 | u8 ibss:1; | ||
37 | u8 cfpollable:1; | ||
38 | u8 cfpollrqst:1; | ||
39 | u8 privacy:1; | ||
40 | u8 shortpreamble:1; | ||
41 | u8 pbcc:1; | ||
42 | u8 chanagility:1; | ||
43 | u8 spectrummgmt:1; | ||
44 | u8 rsrvd3:1; | ||
45 | u8 shortslottime:1; | ||
46 | u8 apsd:1; | ||
47 | u8 rsvrd2:1; | ||
48 | u8 dsssofdm:1; | ||
49 | u8 rsrvd1:2; | ||
50 | } __attribute__ ((packed)); | ||
51 | |||
52 | struct ieeetypes_cfparamset { | ||
53 | u8 elementid; | ||
54 | u8 len; | ||
55 | u8 cfpcnt; | ||
56 | u8 cfpperiod; | ||
57 | u16 cfpmaxduration; | ||
58 | u16 cfpdurationremaining; | ||
59 | } __attribute__ ((packed)); | ||
60 | |||
61 | |||
62 | struct ieeetypes_ibssparamset { | ||
63 | u8 elementid; | ||
64 | u8 len; | ||
65 | u16 atimwindow; | ||
66 | } __attribute__ ((packed)); | ||
67 | |||
68 | union IEEEtypes_ssparamset { | ||
69 | struct ieeetypes_cfparamset cfparamset; | ||
70 | struct ieeetypes_ibssparamset ibssparamset; | ||
71 | } __attribute__ ((packed)); | ||
72 | |||
73 | struct ieeetypes_fhparamset { | ||
74 | u8 elementid; | ||
75 | u8 len; | ||
76 | u16 dwelltime; | ||
77 | u8 hopset; | ||
78 | u8 hoppattern; | ||
79 | u8 hopindex; | ||
80 | } __attribute__ ((packed)); | ||
81 | |||
82 | struct ieeetypes_dsparamset { | ||
83 | u8 elementid; | ||
84 | u8 len; | ||
85 | u8 currentchan; | ||
86 | } __attribute__ ((packed)); | ||
87 | |||
88 | union ieeetypes_phyparamset { | ||
89 | struct ieeetypes_fhparamset fhparamset; | ||
90 | struct ieeetypes_dsparamset dsparamset; | ||
91 | } __attribute__ ((packed)); | ||
92 | |||
93 | struct ieeetypes_assocrsp { | ||
94 | struct ieeetypes_capinfo capability; | ||
95 | u16 statuscode; | ||
96 | u16 aid; | ||
97 | u8 iebuffer[1]; | ||
98 | } __attribute__ ((packed)); | ||
99 | |||
100 | /** TLV type ID definition */ | ||
101 | #define PROPRIETARY_TLV_BASE_ID 0x0100 | ||
102 | |||
103 | /* Terminating TLV type */ | ||
104 | #define MRVL_TERMINATE_TLV_ID 0xffff | ||
105 | |||
106 | #define TLV_TYPE_SSID 0x0000 | ||
107 | #define TLV_TYPE_RATES 0x0001 | ||
108 | #define TLV_TYPE_PHY_FH 0x0002 | ||
109 | #define TLV_TYPE_PHY_DS 0x0003 | ||
110 | #define TLV_TYPE_CF 0x0004 | ||
111 | #define TLV_TYPE_IBSS 0x0006 | ||
112 | |||
113 | #define TLV_TYPE_DOMAIN 0x0007 | ||
114 | |||
115 | #define TLV_TYPE_POWER_CAPABILITY 0x0021 | ||
116 | |||
117 | #define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) | ||
118 | #define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) | ||
119 | #define TLV_TYPE_NUMPROBES (PROPRIETARY_TLV_BASE_ID + 2) | ||
120 | #define TLV_TYPE_RSSI_LOW (PROPRIETARY_TLV_BASE_ID + 4) | ||
121 | #define TLV_TYPE_SNR_LOW (PROPRIETARY_TLV_BASE_ID + 5) | ||
122 | #define TLV_TYPE_FAILCOUNT (PROPRIETARY_TLV_BASE_ID + 6) | ||
123 | #define TLV_TYPE_BCNMISS (PROPRIETARY_TLV_BASE_ID + 7) | ||
124 | #define TLV_TYPE_LED_GPIO (PROPRIETARY_TLV_BASE_ID + 8) | ||
125 | #define TLV_TYPE_LEDBEHAVIOR (PROPRIETARY_TLV_BASE_ID + 9) | ||
126 | #define TLV_TYPE_PASSTHROUGH (PROPRIETARY_TLV_BASE_ID + 10) | ||
127 | #define TLV_TYPE_REASSOCAP (PROPRIETARY_TLV_BASE_ID + 11) | ||
128 | #define TLV_TYPE_POWER_TBL_2_4GHZ (PROPRIETARY_TLV_BASE_ID + 12) | ||
129 | #define TLV_TYPE_POWER_TBL_5GHZ (PROPRIETARY_TLV_BASE_ID + 13) | ||
130 | #define TLV_TYPE_BCASTPROBE (PROPRIETARY_TLV_BASE_ID + 14) | ||
131 | #define TLV_TYPE_NUMSSID_PROBE (PROPRIETARY_TLV_BASE_ID + 15) | ||
132 | #define TLV_TYPE_WMMQSTATUS (PROPRIETARY_TLV_BASE_ID + 16) | ||
133 | #define TLV_TYPE_CRYPTO_DATA (PROPRIETARY_TLV_BASE_ID + 17) | ||
134 | #define TLV_TYPE_WILDCARDSSID (PROPRIETARY_TLV_BASE_ID + 18) | ||
135 | #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) | ||
136 | #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) | ||
137 | #define TLV_TYPE_SNR_HIGH (PROPRIETARY_TLV_BASE_ID + 23) | ||
138 | |||
139 | /** TLV related data structures*/ | ||
140 | struct mrvlietypesheader { | ||
141 | u16 type; | ||
142 | u16 len; | ||
143 | } __attribute__ ((packed)); | ||
144 | |||
145 | struct mrvlietypes_data { | ||
146 | struct mrvlietypesheader header; | ||
147 | u8 Data[1]; | ||
148 | } __attribute__ ((packed)); | ||
149 | |||
150 | struct mrvlietypes_ratesparamset { | ||
151 | struct mrvlietypesheader header; | ||
152 | u8 rates[1]; | ||
153 | } __attribute__ ((packed)); | ||
154 | |||
155 | struct mrvlietypes_ssidparamset { | ||
156 | struct mrvlietypesheader header; | ||
157 | u8 ssid[1]; | ||
158 | } __attribute__ ((packed)); | ||
159 | |||
160 | struct mrvlietypes_wildcardssidparamset { | ||
161 | struct mrvlietypesheader header; | ||
162 | u8 MaxSsidlength; | ||
163 | u8 ssid[1]; | ||
164 | } __attribute__ ((packed)); | ||
165 | |||
166 | struct chanscanmode { | ||
167 | u8 passivescan:1; | ||
168 | u8 disablechanfilt:1; | ||
169 | u8 reserved_2_7:6; | ||
170 | } __attribute__ ((packed)); | ||
171 | |||
172 | struct chanscanparamset { | ||
173 | u8 radiotype; | ||
174 | u8 channumber; | ||
175 | struct chanscanmode chanscanmode; | ||
176 | u16 minscantime; | ||
177 | u16 maxscantime; | ||
178 | } __attribute__ ((packed)); | ||
179 | |||
180 | struct mrvlietypes_chanlistparamset { | ||
181 | struct mrvlietypesheader header; | ||
182 | struct chanscanparamset chanscanparam[1]; | ||
183 | } __attribute__ ((packed)); | ||
184 | |||
185 | struct cfparamset { | ||
186 | u8 cfpcnt; | ||
187 | u8 cfpperiod; | ||
188 | u16 cfpmaxduration; | ||
189 | u16 cfpdurationremaining; | ||
190 | } __attribute__ ((packed)); | ||
191 | |||
192 | struct ibssparamset { | ||
193 | u16 atimwindow; | ||
194 | } __attribute__ ((packed)); | ||
195 | |||
196 | struct mrvlietypes_ssparamset { | ||
197 | struct mrvlietypesheader header; | ||
198 | union { | ||
199 | struct cfparamset cfparamset[1]; | ||
200 | struct ibssparamset ibssparamset[1]; | ||
201 | } cf_ibss; | ||
202 | } __attribute__ ((packed)); | ||
203 | |||
204 | struct fhparamset { | ||
205 | u16 dwelltime; | ||
206 | u8 hopset; | ||
207 | u8 hoppattern; | ||
208 | u8 hopindex; | ||
209 | } __attribute__ ((packed)); | ||
210 | |||
211 | struct dsparamset { | ||
212 | u8 currentchan; | ||
213 | } __attribute__ ((packed)); | ||
214 | |||
215 | struct mrvlietypes_phyparamset { | ||
216 | struct mrvlietypesheader header; | ||
217 | union { | ||
218 | struct fhparamset fhparamset[1]; | ||
219 | struct dsparamset dsparamset[1]; | ||
220 | } fh_ds; | ||
221 | } __attribute__ ((packed)); | ||
222 | |||
223 | struct mrvlietypes_rsnparamset { | ||
224 | struct mrvlietypesheader header; | ||
225 | u8 rsnie[1]; | ||
226 | } __attribute__ ((packed)); | ||
227 | |||
228 | struct mrvlietypes_tsftimestamp { | ||
229 | struct mrvlietypesheader header; | ||
230 | __le64 tsftable[1]; | ||
231 | } __attribute__ ((packed)); | ||
232 | |||
233 | /** Local Power capability */ | ||
234 | struct mrvlietypes_powercapability { | ||
235 | struct mrvlietypesheader header; | ||
236 | s8 minpower; | ||
237 | s8 maxpower; | ||
238 | } __attribute__ ((packed)); | ||
239 | |||
240 | struct mrvlietypes_rssithreshold { | ||
241 | struct mrvlietypesheader header; | ||
242 | u8 rssivalue; | ||
243 | u8 rssifreq; | ||
244 | } __attribute__ ((packed)); | ||
245 | |||
246 | struct mrvlietypes_snrthreshold { | ||
247 | struct mrvlietypesheader header; | ||
248 | u8 snrvalue; | ||
249 | u8 snrfreq; | ||
250 | } __attribute__ ((packed)); | ||
251 | |||
252 | struct mrvlietypes_failurecount { | ||
253 | struct mrvlietypesheader header; | ||
254 | u8 failvalue; | ||
255 | u8 Failfreq; | ||
256 | } __attribute__ ((packed)); | ||
257 | |||
258 | struct mrvlietypes_beaconsmissed { | ||
259 | struct mrvlietypesheader header; | ||
260 | u8 beaconmissed; | ||
261 | u8 reserved; | ||
262 | } __attribute__ ((packed)); | ||
263 | |||
264 | struct mrvlietypes_numprobes { | ||
265 | struct mrvlietypesheader header; | ||
266 | u16 numprobes; | ||
267 | } __attribute__ ((packed)); | ||
268 | |||
269 | struct mrvlietypes_bcastprobe { | ||
270 | struct mrvlietypesheader header; | ||
271 | u16 bcastprobe; | ||
272 | } __attribute__ ((packed)); | ||
273 | |||
274 | struct mrvlietypes_numssidprobe { | ||
275 | struct mrvlietypesheader header; | ||
276 | u16 numssidprobe; | ||
277 | } __attribute__ ((packed)); | ||
278 | |||
279 | struct led_pin { | ||
280 | u8 led; | ||
281 | u8 pin; | ||
282 | } __attribute__ ((packed)); | ||
283 | |||
284 | struct mrvlietypes_ledgpio { | ||
285 | struct mrvlietypesheader header; | ||
286 | struct led_pin ledpin[1]; | ||
287 | } __attribute__ ((packed)); | ||
288 | |||
289 | #endif /* _WLAN_TYPES_ */ | ||
diff --git a/drivers/net/wireless/libertas/version.h b/drivers/net/wireless/libertas/version.h new file mode 100644 index 000000000000..e86f65ae79b8 --- /dev/null +++ b/drivers/net/wireless/libertas/version.h | |||
@@ -0,0 +1,8 @@ | |||
1 | #define DRIVER_RELEASE_VERSION "320.p0" | ||
2 | const char libertas_driver_version[] = "COMM-USB8388-" DRIVER_RELEASE_VERSION | ||
3 | #ifdef DEBUG | ||
4 | "-dbg" | ||
5 | #endif | ||
6 | ""; | ||
7 | |||
8 | |||
diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c new file mode 100644 index 000000000000..4a52336bc0f6 --- /dev/null +++ b/drivers/net/wireless/libertas/wext.c | |||
@@ -0,0 +1,2769 @@ | |||
1 | /** | ||
2 | * This file contains ioctl functions | ||
3 | */ | ||
4 | #include <linux/ctype.h> | ||
5 | #include <linux/delay.h> | ||
6 | #include <linux/if.h> | ||
7 | #include <linux/if_arp.h> | ||
8 | #include <linux/wireless.h> | ||
9 | #include <linux/bitops.h> | ||
10 | |||
11 | #include <net/ieee80211.h> | ||
12 | #include <net/iw_handler.h> | ||
13 | |||
14 | #include "host.h" | ||
15 | #include "radiotap.h" | ||
16 | #include "decl.h" | ||
17 | #include "defs.h" | ||
18 | #include "dev.h" | ||
19 | #include "join.h" | ||
20 | #include "version.h" | ||
21 | #include "wext.h" | ||
22 | #include "assoc.h" | ||
23 | |||
24 | |||
25 | /** | ||
26 | * @brief Convert mw value to dbm value | ||
27 | * | ||
28 | * @param mw the value of mw | ||
29 | * @return the value of dbm | ||
30 | */ | ||
31 | static int mw_to_dbm(int mw) | ||
32 | { | ||
33 | if (mw < 2) | ||
34 | return 0; | ||
35 | else if (mw < 3) | ||
36 | return 3; | ||
37 | else if (mw < 4) | ||
38 | return 5; | ||
39 | else if (mw < 6) | ||
40 | return 7; | ||
41 | else if (mw < 7) | ||
42 | return 8; | ||
43 | else if (mw < 8) | ||
44 | return 9; | ||
45 | else if (mw < 10) | ||
46 | return 10; | ||
47 | else if (mw < 13) | ||
48 | return 11; | ||
49 | else if (mw < 16) | ||
50 | return 12; | ||
51 | else if (mw < 20) | ||
52 | return 13; | ||
53 | else if (mw < 25) | ||
54 | return 14; | ||
55 | else if (mw < 32) | ||
56 | return 15; | ||
57 | else if (mw < 40) | ||
58 | return 16; | ||
59 | else if (mw < 50) | ||
60 | return 17; | ||
61 | else if (mw < 63) | ||
62 | return 18; | ||
63 | else if (mw < 79) | ||
64 | return 19; | ||
65 | else if (mw < 100) | ||
66 | return 20; | ||
67 | else | ||
68 | return 21; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * @brief Find the channel frequency power info with specific channel | ||
73 | * | ||
74 | * @param adapter A pointer to wlan_adapter structure | ||
75 | * @param band it can be BAND_A, BAND_G or BAND_B | ||
76 | * @param channel the channel for looking | ||
77 | * @return A pointer to struct chan_freq_power structure or NULL if not find. | ||
78 | */ | ||
79 | struct chan_freq_power *libertas_find_cfp_by_band_and_channel(wlan_adapter * adapter, | ||
80 | u8 band, u16 channel) | ||
81 | { | ||
82 | struct chan_freq_power *cfp = NULL; | ||
83 | struct region_channel *rc; | ||
84 | int count = sizeof(adapter->region_channel) / | ||
85 | sizeof(adapter->region_channel[0]); | ||
86 | int i, j; | ||
87 | |||
88 | for (j = 0; !cfp && (j < count); j++) { | ||
89 | rc = &adapter->region_channel[j]; | ||
90 | |||
91 | if (adapter->enable11d) | ||
92 | rc = &adapter->universal_channel[j]; | ||
93 | if (!rc->valid || !rc->CFP) | ||
94 | continue; | ||
95 | if (rc->band != band) | ||
96 | continue; | ||
97 | for (i = 0; i < rc->nrcfp; i++) { | ||
98 | if (rc->CFP[i].channel == channel) { | ||
99 | cfp = &rc->CFP[i]; | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | |||
105 | if (!cfp && channel) | ||
106 | lbs_pr_debug(1, "libertas_find_cfp_by_band_and_channel(): cannot find " | ||
107 | "cfp by band %d & channel %d\n", band, channel); | ||
108 | |||
109 | return cfp; | ||
110 | } | ||
111 | |||
112 | /** | ||
113 | * @brief Find the channel frequency power info with specific frequency | ||
114 | * | ||
115 | * @param adapter A pointer to wlan_adapter structure | ||
116 | * @param band it can be BAND_A, BAND_G or BAND_B | ||
117 | * @param freq the frequency for looking | ||
118 | * @return A pointer to struct chan_freq_power structure or NULL if not find. | ||
119 | */ | ||
120 | static struct chan_freq_power *find_cfp_by_band_and_freq(wlan_adapter * adapter, | ||
121 | u8 band, u32 freq) | ||
122 | { | ||
123 | struct chan_freq_power *cfp = NULL; | ||
124 | struct region_channel *rc; | ||
125 | int count = sizeof(adapter->region_channel) / | ||
126 | sizeof(adapter->region_channel[0]); | ||
127 | int i, j; | ||
128 | |||
129 | for (j = 0; !cfp && (j < count); j++) { | ||
130 | rc = &adapter->region_channel[j]; | ||
131 | |||
132 | if (adapter->enable11d) | ||
133 | rc = &adapter->universal_channel[j]; | ||
134 | if (!rc->valid || !rc->CFP) | ||
135 | continue; | ||
136 | if (rc->band != band) | ||
137 | continue; | ||
138 | for (i = 0; i < rc->nrcfp; i++) { | ||
139 | if (rc->CFP[i].freq == freq) { | ||
140 | cfp = &rc->CFP[i]; | ||
141 | break; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | if (!cfp && freq) | ||
147 | lbs_pr_debug(1, "find_cfp_by_band_and_freql(): cannot find cfp by " | ||
148 | "band %d & freq %d\n", band, freq); | ||
149 | |||
150 | return cfp; | ||
151 | } | ||
152 | |||
153 | static int updatecurrentchannel(wlan_private * priv) | ||
154 | { | ||
155 | int ret; | ||
156 | |||
157 | /* | ||
158 | ** the channel in f/w could be out of sync, get the current channel | ||
159 | */ | ||
160 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, | ||
161 | cmd_opt_802_11_rf_channel_get, | ||
162 | cmd_option_waitforrsp, 0, NULL); | ||
163 | |||
164 | lbs_pr_debug(1, "Current channel = %d\n", | ||
165 | priv->adapter->curbssparams.channel); | ||
166 | |||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | static int setcurrentchannel(wlan_private * priv, int channel) | ||
171 | { | ||
172 | lbs_pr_debug(1, "Set channel = %d\n", channel); | ||
173 | |||
174 | /* | ||
175 | ** Current channel is not set to adhocchannel requested, set channel | ||
176 | */ | ||
177 | return (libertas_prepare_and_send_command(priv, cmd_802_11_rf_channel, | ||
178 | cmd_opt_802_11_rf_channel_set, | ||
179 | cmd_option_waitforrsp, 0, &channel)); | ||
180 | } | ||
181 | |||
182 | static int changeadhocchannel(wlan_private * priv, int channel) | ||
183 | { | ||
184 | int ret = 0; | ||
185 | wlan_adapter *adapter = priv->adapter; | ||
186 | |||
187 | adapter->adhocchannel = channel; | ||
188 | |||
189 | updatecurrentchannel(priv); | ||
190 | |||
191 | if (adapter->curbssparams.channel == adapter->adhocchannel) { | ||
192 | /* adhocchannel is set to the current channel already */ | ||
193 | LEAVE(); | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | lbs_pr_debug(1, "Updating channel from %d to %d\n", | ||
198 | adapter->curbssparams.channel, adapter->adhocchannel); | ||
199 | |||
200 | setcurrentchannel(priv, adapter->adhocchannel); | ||
201 | |||
202 | updatecurrentchannel(priv); | ||
203 | |||
204 | if (adapter->curbssparams.channel != adapter->adhocchannel) { | ||
205 | lbs_pr_debug(1, "failed to updated channel to %d, channel = %d\n", | ||
206 | adapter->adhocchannel, adapter->curbssparams.channel); | ||
207 | LEAVE(); | ||
208 | return -1; | ||
209 | } | ||
210 | |||
211 | if (adapter->connect_status == libertas_connected) { | ||
212 | int i; | ||
213 | struct WLAN_802_11_SSID curadhocssid; | ||
214 | |||
215 | lbs_pr_debug(1, "channel Changed while in an IBSS\n"); | ||
216 | |||
217 | /* Copy the current ssid */ | ||
218 | memcpy(&curadhocssid, &adapter->curbssparams.ssid, | ||
219 | sizeof(struct WLAN_802_11_SSID)); | ||
220 | |||
221 | /* Exit Adhoc mode */ | ||
222 | lbs_pr_debug(1, "In changeadhocchannel(): Sending Adhoc Stop\n"); | ||
223 | ret = libertas_stop_adhoc_network(priv); | ||
224 | |||
225 | if (ret) { | ||
226 | LEAVE(); | ||
227 | return ret; | ||
228 | } | ||
229 | /* Scan for the network, do not save previous results. Stale | ||
230 | * scan data will cause us to join a non-existant adhoc network | ||
231 | */ | ||
232 | libertas_send_specific_SSID_scan(priv, &curadhocssid, 0); | ||
233 | |||
234 | // find out the BSSID that matches the current SSID | ||
235 | i = libertas_find_SSID_in_list(adapter, &curadhocssid, NULL, | ||
236 | wlan802_11ibss); | ||
237 | |||
238 | if (i >= 0) { | ||
239 | lbs_pr_debug(1, "SSID found at %d in List," | ||
240 | "so join\n", i); | ||
241 | libertas_join_adhoc_network(priv, &adapter->scantable[i]); | ||
242 | } else { | ||
243 | // else send START command | ||
244 | lbs_pr_debug(1, "SSID not found in list, " | ||
245 | "so creating adhoc with ssid = %s\n", | ||
246 | curadhocssid.ssid); | ||
247 | libertas_start_adhoc_network(priv, &curadhocssid); | ||
248 | } // end of else (START command) | ||
249 | } | ||
250 | |||
251 | LEAVE(); | ||
252 | return 0; | ||
253 | } | ||
254 | |||
255 | /** | ||
256 | * @brief Set Radio On/OFF | ||
257 | * | ||
258 | * @param priv A pointer to wlan_private structure | ||
259 | * @option Radio Option | ||
260 | * @return 0 --success, otherwise fail | ||
261 | */ | ||
262 | int wlan_radio_ioctl(wlan_private * priv, u8 option) | ||
263 | { | ||
264 | int ret = 0; | ||
265 | wlan_adapter *adapter = priv->adapter; | ||
266 | |||
267 | ENTER(); | ||
268 | |||
269 | if (adapter->radioon != option) { | ||
270 | lbs_pr_debug(1, "Switching %s the Radio\n", option ? "On" : "Off"); | ||
271 | adapter->radioon = option; | ||
272 | |||
273 | ret = libertas_prepare_and_send_command(priv, | ||
274 | cmd_802_11_radio_control, | ||
275 | cmd_act_set, | ||
276 | cmd_option_waitforrsp, 0, NULL); | ||
277 | } | ||
278 | |||
279 | LEAVE(); | ||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | /** | ||
284 | * @brief Copy rates | ||
285 | * | ||
286 | * @param dest A pointer to Dest Buf | ||
287 | * @param src A pointer to Src Buf | ||
288 | * @param len The len of Src Buf | ||
289 | * @return Number of rates copyed | ||
290 | */ | ||
291 | static inline int copyrates(u8 * dest, int pos, u8 * src, int len) | ||
292 | { | ||
293 | int i; | ||
294 | |||
295 | for (i = 0; i < len && src[i]; i++, pos++) { | ||
296 | if (pos >= sizeof(u8) * WLAN_SUPPORTED_RATES) | ||
297 | break; | ||
298 | dest[pos] = src[i]; | ||
299 | } | ||
300 | |||
301 | return pos; | ||
302 | } | ||
303 | |||
304 | /** | ||
305 | * @brief Get active data rates | ||
306 | * | ||
307 | * @param adapter A pointer to wlan_adapter structure | ||
308 | * @param rate The buf to return the active rates | ||
309 | * @return The number of rates | ||
310 | */ | ||
311 | static int get_active_data_rates(wlan_adapter * adapter, | ||
312 | u8* rates) | ||
313 | { | ||
314 | int k = 0; | ||
315 | |||
316 | ENTER(); | ||
317 | |||
318 | if (adapter->connect_status != libertas_connected) { | ||
319 | if (adapter->inframode == wlan802_11infrastructure) { | ||
320 | //Infra. mode | ||
321 | lbs_pr_debug(1, "Infra\n"); | ||
322 | k = copyrates(rates, k, libertas_supported_rates, | ||
323 | sizeof(libertas_supported_rates)); | ||
324 | } else { | ||
325 | //ad-hoc mode | ||
326 | lbs_pr_debug(1, "Adhoc G\n"); | ||
327 | k = copyrates(rates, k, libertas_adhoc_rates_g, | ||
328 | sizeof(libertas_adhoc_rates_g)); | ||
329 | } | ||
330 | } else { | ||
331 | k = copyrates(rates, 0, adapter->curbssparams.datarates, | ||
332 | adapter->curbssparams.numofrates); | ||
333 | } | ||
334 | |||
335 | LEAVE(); | ||
336 | |||
337 | return k; | ||
338 | } | ||
339 | |||
340 | static int wlan_get_name(struct net_device *dev, struct iw_request_info *info, | ||
341 | char *cwrq, char *extra) | ||
342 | { | ||
343 | const char *cp; | ||
344 | char comm[6] = { "COMM-" }; | ||
345 | char mrvl[6] = { "MRVL-" }; | ||
346 | int cnt; | ||
347 | |||
348 | ENTER(); | ||
349 | |||
350 | strcpy(cwrq, mrvl); | ||
351 | |||
352 | cp = strstr(libertas_driver_version, comm); | ||
353 | if (cp == libertas_driver_version) //skip leading "COMM-" | ||
354 | cp = libertas_driver_version + strlen(comm); | ||
355 | else | ||
356 | cp = libertas_driver_version; | ||
357 | |||
358 | cnt = strlen(mrvl); | ||
359 | cwrq += cnt; | ||
360 | while (cnt < 16 && (*cp != '-')) { | ||
361 | *cwrq++ = toupper(*cp++); | ||
362 | cnt++; | ||
363 | } | ||
364 | *cwrq = '\0'; | ||
365 | |||
366 | LEAVE(); | ||
367 | |||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static int wlan_get_freq(struct net_device *dev, struct iw_request_info *info, | ||
372 | struct iw_freq *fwrq, char *extra) | ||
373 | { | ||
374 | wlan_private *priv = dev->priv; | ||
375 | wlan_adapter *adapter = priv->adapter; | ||
376 | struct chan_freq_power *cfp; | ||
377 | |||
378 | ENTER(); | ||
379 | |||
380 | cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, | ||
381 | adapter->curbssparams.channel); | ||
382 | |||
383 | if (!cfp) { | ||
384 | if (adapter->curbssparams.channel) | ||
385 | lbs_pr_debug(1, "Invalid channel=%d\n", | ||
386 | adapter->curbssparams.channel); | ||
387 | return -EINVAL; | ||
388 | } | ||
389 | |||
390 | fwrq->m = (long)cfp->freq * 100000; | ||
391 | fwrq->e = 1; | ||
392 | |||
393 | lbs_pr_debug(1, "freq=%u\n", fwrq->m); | ||
394 | |||
395 | LEAVE(); | ||
396 | return 0; | ||
397 | } | ||
398 | |||
399 | static int wlan_get_wap(struct net_device *dev, struct iw_request_info *info, | ||
400 | struct sockaddr *awrq, char *extra) | ||
401 | { | ||
402 | wlan_private *priv = dev->priv; | ||
403 | wlan_adapter *adapter = priv->adapter; | ||
404 | |||
405 | ENTER(); | ||
406 | |||
407 | if (adapter->connect_status == libertas_connected) { | ||
408 | memcpy(awrq->sa_data, adapter->curbssparams.bssid, ETH_ALEN); | ||
409 | } else { | ||
410 | memset(awrq->sa_data, 0, ETH_ALEN); | ||
411 | } | ||
412 | awrq->sa_family = ARPHRD_ETHER; | ||
413 | |||
414 | LEAVE(); | ||
415 | return 0; | ||
416 | } | ||
417 | |||
418 | static int wlan_set_nick(struct net_device *dev, struct iw_request_info *info, | ||
419 | struct iw_point *dwrq, char *extra) | ||
420 | { | ||
421 | wlan_private *priv = dev->priv; | ||
422 | wlan_adapter *adapter = priv->adapter; | ||
423 | |||
424 | ENTER(); | ||
425 | |||
426 | /* | ||
427 | * Check the size of the string | ||
428 | */ | ||
429 | |||
430 | if (dwrq->length > 16) { | ||
431 | return -E2BIG; | ||
432 | } | ||
433 | |||
434 | mutex_lock(&adapter->lock); | ||
435 | memset(adapter->nodename, 0, sizeof(adapter->nodename)); | ||
436 | memcpy(adapter->nodename, extra, dwrq->length); | ||
437 | mutex_unlock(&adapter->lock); | ||
438 | |||
439 | LEAVE(); | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int wlan_get_nick(struct net_device *dev, struct iw_request_info *info, | ||
444 | struct iw_point *dwrq, char *extra) | ||
445 | { | ||
446 | wlan_private *priv = dev->priv; | ||
447 | wlan_adapter *adapter = priv->adapter; | ||
448 | |||
449 | ENTER(); | ||
450 | |||
451 | /* | ||
452 | * Get the Nick Name saved | ||
453 | */ | ||
454 | |||
455 | mutex_lock(&adapter->lock); | ||
456 | strncpy(extra, adapter->nodename, 16); | ||
457 | mutex_unlock(&adapter->lock); | ||
458 | |||
459 | extra[16] = '\0'; | ||
460 | |||
461 | /* | ||
462 | * If none, we may want to get the one that was set | ||
463 | */ | ||
464 | |||
465 | /* | ||
466 | * Push it out ! | ||
467 | */ | ||
468 | dwrq->length = strlen(extra) + 1; | ||
469 | |||
470 | LEAVE(); | ||
471 | return 0; | ||
472 | } | ||
473 | |||
474 | static int wlan_set_rts(struct net_device *dev, struct iw_request_info *info, | ||
475 | struct iw_param *vwrq, char *extra) | ||
476 | { | ||
477 | int ret = 0; | ||
478 | wlan_private *priv = dev->priv; | ||
479 | wlan_adapter *adapter = priv->adapter; | ||
480 | int rthr = vwrq->value; | ||
481 | |||
482 | ENTER(); | ||
483 | |||
484 | if (vwrq->disabled) { | ||
485 | adapter->rtsthsd = rthr = MRVDRV_RTS_MAX_VALUE; | ||
486 | } else { | ||
487 | if (rthr < MRVDRV_RTS_MIN_VALUE || rthr > MRVDRV_RTS_MAX_VALUE) | ||
488 | return -EINVAL; | ||
489 | adapter->rtsthsd = rthr; | ||
490 | } | ||
491 | |||
492 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, | ||
493 | cmd_act_set, cmd_option_waitforrsp, | ||
494 | OID_802_11_RTS_THRESHOLD, &rthr); | ||
495 | |||
496 | LEAVE(); | ||
497 | return ret; | ||
498 | } | ||
499 | |||
500 | static int wlan_get_rts(struct net_device *dev, struct iw_request_info *info, | ||
501 | struct iw_param *vwrq, char *extra) | ||
502 | { | ||
503 | int ret = 0; | ||
504 | wlan_private *priv = dev->priv; | ||
505 | wlan_adapter *adapter = priv->adapter; | ||
506 | |||
507 | ENTER(); | ||
508 | |||
509 | adapter->rtsthsd = 0; | ||
510 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, | ||
511 | cmd_act_get, cmd_option_waitforrsp, | ||
512 | OID_802_11_RTS_THRESHOLD, NULL); | ||
513 | if (ret) { | ||
514 | LEAVE(); | ||
515 | return ret; | ||
516 | } | ||
517 | |||
518 | vwrq->value = adapter->rtsthsd; | ||
519 | vwrq->disabled = ((vwrq->value < MRVDRV_RTS_MIN_VALUE) | ||
520 | || (vwrq->value > MRVDRV_RTS_MAX_VALUE)); | ||
521 | vwrq->fixed = 1; | ||
522 | |||
523 | LEAVE(); | ||
524 | return 0; | ||
525 | } | ||
526 | |||
527 | static int wlan_set_frag(struct net_device *dev, struct iw_request_info *info, | ||
528 | struct iw_param *vwrq, char *extra) | ||
529 | { | ||
530 | int ret = 0; | ||
531 | int fthr = vwrq->value; | ||
532 | wlan_private *priv = dev->priv; | ||
533 | wlan_adapter *adapter = priv->adapter; | ||
534 | |||
535 | ENTER(); | ||
536 | |||
537 | if (vwrq->disabled) { | ||
538 | adapter->fragthsd = fthr = MRVDRV_FRAG_MAX_VALUE; | ||
539 | } else { | ||
540 | if (fthr < MRVDRV_FRAG_MIN_VALUE | ||
541 | || fthr > MRVDRV_FRAG_MAX_VALUE) | ||
542 | return -EINVAL; | ||
543 | adapter->fragthsd = fthr; | ||
544 | } | ||
545 | |||
546 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, | ||
547 | cmd_act_set, cmd_option_waitforrsp, | ||
548 | OID_802_11_FRAGMENTATION_THRESHOLD, &fthr); | ||
549 | LEAVE(); | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | static int wlan_get_frag(struct net_device *dev, struct iw_request_info *info, | ||
554 | struct iw_param *vwrq, char *extra) | ||
555 | { | ||
556 | int ret = 0; | ||
557 | wlan_private *priv = dev->priv; | ||
558 | wlan_adapter *adapter = priv->adapter; | ||
559 | |||
560 | ENTER(); | ||
561 | |||
562 | adapter->fragthsd = 0; | ||
563 | ret = libertas_prepare_and_send_command(priv, | ||
564 | cmd_802_11_snmp_mib, | ||
565 | cmd_act_get, cmd_option_waitforrsp, | ||
566 | OID_802_11_FRAGMENTATION_THRESHOLD, NULL); | ||
567 | if (ret) { | ||
568 | LEAVE(); | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | vwrq->value = adapter->fragthsd; | ||
573 | vwrq->disabled = ((vwrq->value < MRVDRV_FRAG_MIN_VALUE) | ||
574 | || (vwrq->value > MRVDRV_FRAG_MAX_VALUE)); | ||
575 | vwrq->fixed = 1; | ||
576 | |||
577 | LEAVE(); | ||
578 | return ret; | ||
579 | } | ||
580 | |||
581 | static int wlan_get_mode(struct net_device *dev, | ||
582 | struct iw_request_info *info, u32 * uwrq, char *extra) | ||
583 | { | ||
584 | wlan_private *priv = dev->priv; | ||
585 | wlan_adapter *adapter = priv->adapter; | ||
586 | |||
587 | ENTER(); | ||
588 | |||
589 | switch (adapter->inframode) { | ||
590 | case wlan802_11ibss: | ||
591 | *uwrq = IW_MODE_ADHOC; | ||
592 | break; | ||
593 | |||
594 | case wlan802_11infrastructure: | ||
595 | *uwrq = IW_MODE_INFRA; | ||
596 | break; | ||
597 | |||
598 | default: | ||
599 | case wlan802_11autounknown: | ||
600 | *uwrq = IW_MODE_AUTO; | ||
601 | break; | ||
602 | } | ||
603 | |||
604 | LEAVE(); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static int wlan_get_txpow(struct net_device *dev, | ||
609 | struct iw_request_info *info, | ||
610 | struct iw_param *vwrq, char *extra) | ||
611 | { | ||
612 | int ret = 0; | ||
613 | wlan_private *priv = dev->priv; | ||
614 | wlan_adapter *adapter = priv->adapter; | ||
615 | |||
616 | ENTER(); | ||
617 | |||
618 | ret = libertas_prepare_and_send_command(priv, | ||
619 | cmd_802_11_rf_tx_power, | ||
620 | cmd_act_tx_power_opt_get, | ||
621 | cmd_option_waitforrsp, 0, NULL); | ||
622 | |||
623 | if (ret) { | ||
624 | LEAVE(); | ||
625 | return ret; | ||
626 | } | ||
627 | |||
628 | lbs_pr_debug(1, "TXPOWER GET %d dbm.\n", adapter->txpowerlevel); | ||
629 | vwrq->value = adapter->txpowerlevel; | ||
630 | vwrq->fixed = 1; | ||
631 | if (adapter->radioon) { | ||
632 | vwrq->disabled = 0; | ||
633 | vwrq->flags = IW_TXPOW_DBM; | ||
634 | } else { | ||
635 | vwrq->disabled = 1; | ||
636 | } | ||
637 | |||
638 | LEAVE(); | ||
639 | return 0; | ||
640 | } | ||
641 | |||
642 | static int wlan_set_retry(struct net_device *dev, struct iw_request_info *info, | ||
643 | struct iw_param *vwrq, char *extra) | ||
644 | { | ||
645 | int ret = 0; | ||
646 | wlan_private *priv = dev->priv; | ||
647 | wlan_adapter *adapter = priv->adapter; | ||
648 | |||
649 | ENTER(); | ||
650 | |||
651 | if (vwrq->flags == IW_RETRY_LIMIT) { | ||
652 | /* The MAC has a 4-bit Total_Tx_Count register | ||
653 | Total_Tx_Count = 1 + Tx_Retry_Count */ | ||
654 | #define TX_RETRY_MIN 0 | ||
655 | #define TX_RETRY_MAX 14 | ||
656 | if (vwrq->value < TX_RETRY_MIN || vwrq->value > TX_RETRY_MAX) | ||
657 | return -EINVAL; | ||
658 | |||
659 | /* Adding 1 to convert retry count to try count */ | ||
660 | adapter->txretrycount = vwrq->value + 1; | ||
661 | |||
662 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_snmp_mib, | ||
663 | cmd_act_set, | ||
664 | cmd_option_waitforrsp, | ||
665 | OID_802_11_TX_RETRYCOUNT, NULL); | ||
666 | |||
667 | if (ret) { | ||
668 | LEAVE(); | ||
669 | return ret; | ||
670 | } | ||
671 | } else { | ||
672 | return -EOPNOTSUPP; | ||
673 | } | ||
674 | |||
675 | LEAVE(); | ||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int wlan_get_retry(struct net_device *dev, struct iw_request_info *info, | ||
680 | struct iw_param *vwrq, char *extra) | ||
681 | { | ||
682 | wlan_private *priv = dev->priv; | ||
683 | wlan_adapter *adapter = priv->adapter; | ||
684 | int ret = 0; | ||
685 | |||
686 | ENTER(); | ||
687 | adapter->txretrycount = 0; | ||
688 | ret = libertas_prepare_and_send_command(priv, | ||
689 | cmd_802_11_snmp_mib, | ||
690 | cmd_act_get, cmd_option_waitforrsp, | ||
691 | OID_802_11_TX_RETRYCOUNT, NULL); | ||
692 | if (ret) { | ||
693 | LEAVE(); | ||
694 | return ret; | ||
695 | } | ||
696 | vwrq->disabled = 0; | ||
697 | if (!vwrq->flags) { | ||
698 | vwrq->flags = IW_RETRY_LIMIT; | ||
699 | /* Subtract 1 to convert try count to retry count */ | ||
700 | vwrq->value = adapter->txretrycount - 1; | ||
701 | } | ||
702 | |||
703 | LEAVE(); | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | static inline void sort_channels(struct iw_freq *freq, int num) | ||
708 | { | ||
709 | int i, j; | ||
710 | struct iw_freq temp; | ||
711 | |||
712 | for (i = 0; i < num; i++) | ||
713 | for (j = i + 1; j < num; j++) | ||
714 | if (freq[i].i > freq[j].i) { | ||
715 | temp.i = freq[i].i; | ||
716 | temp.m = freq[i].m; | ||
717 | |||
718 | freq[i].i = freq[j].i; | ||
719 | freq[i].m = freq[j].m; | ||
720 | |||
721 | freq[j].i = temp.i; | ||
722 | freq[j].m = temp.m; | ||
723 | } | ||
724 | } | ||
725 | |||
726 | /* data rate listing | ||
727 | MULTI_BANDS: | ||
728 | abg a b b/g | ||
729 | Infra G(12) A(8) B(4) G(12) | ||
730 | Adhoc A+B(12) A(8) B(4) B(4) | ||
731 | |||
732 | non-MULTI_BANDS: | ||
733 | b b/g | ||
734 | Infra B(4) G(12) | ||
735 | Adhoc B(4) B(4) | ||
736 | */ | ||
737 | /** | ||
738 | * @brief Get Range Info | ||
739 | * | ||
740 | * @param dev A pointer to net_device structure | ||
741 | * @param info A pointer to iw_request_info structure | ||
742 | * @param vwrq A pointer to iw_param structure | ||
743 | * @param extra A pointer to extra data buf | ||
744 | * @return 0 --success, otherwise fail | ||
745 | */ | ||
746 | static int wlan_get_range(struct net_device *dev, struct iw_request_info *info, | ||
747 | struct iw_point *dwrq, char *extra) | ||
748 | { | ||
749 | int i, j; | ||
750 | wlan_private *priv = dev->priv; | ||
751 | wlan_adapter *adapter = priv->adapter; | ||
752 | struct iw_range *range = (struct iw_range *)extra; | ||
753 | struct chan_freq_power *cfp; | ||
754 | u8 rates[WLAN_SUPPORTED_RATES]; | ||
755 | |||
756 | u8 flag = 0; | ||
757 | |||
758 | ENTER(); | ||
759 | |||
760 | dwrq->length = sizeof(struct iw_range); | ||
761 | memset(range, 0, sizeof(struct iw_range)); | ||
762 | |||
763 | range->min_nwid = 0; | ||
764 | range->max_nwid = 0; | ||
765 | |||
766 | memset(rates, 0, sizeof(rates)); | ||
767 | range->num_bitrates = get_active_data_rates(adapter, rates); | ||
768 | |||
769 | for (i = 0; i < min_t(__u8, range->num_bitrates, IW_MAX_BITRATES) && rates[i]; | ||
770 | i++) { | ||
771 | range->bitrate[i] = (rates[i] & 0x7f) * 500000; | ||
772 | } | ||
773 | range->num_bitrates = i; | ||
774 | lbs_pr_debug(1, "IW_MAX_BITRATES=%d num_bitrates=%d\n", IW_MAX_BITRATES, | ||
775 | range->num_bitrates); | ||
776 | |||
777 | range->num_frequency = 0; | ||
778 | if (priv->adapter->enable11d && | ||
779 | adapter->connect_status == libertas_connected) { | ||
780 | u8 chan_no; | ||
781 | u8 band; | ||
782 | |||
783 | struct parsed_region_chan_11d *parsed_region_chan = | ||
784 | &adapter->parsed_region_chan; | ||
785 | |||
786 | if (parsed_region_chan == NULL) { | ||
787 | lbs_pr_debug(1, "11D:parsed_region_chan is NULL\n"); | ||
788 | LEAVE(); | ||
789 | return 0; | ||
790 | } | ||
791 | band = parsed_region_chan->band; | ||
792 | lbs_pr_debug(1, "band=%d NoOfChan=%d\n", band, | ||
793 | parsed_region_chan->nr_chan); | ||
794 | |||
795 | for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) | ||
796 | && (i < parsed_region_chan->nr_chan); i++) { | ||
797 | chan_no = parsed_region_chan->chanpwr[i].chan; | ||
798 | lbs_pr_debug(1, "chan_no=%d\n", chan_no); | ||
799 | range->freq[range->num_frequency].i = (long)chan_no; | ||
800 | range->freq[range->num_frequency].m = | ||
801 | (long)libertas_chan_2_freq(chan_no, band) * 100000; | ||
802 | range->freq[range->num_frequency].e = 1; | ||
803 | range->num_frequency++; | ||
804 | } | ||
805 | flag = 1; | ||
806 | } | ||
807 | if (!flag) { | ||
808 | for (j = 0; (range->num_frequency < IW_MAX_FREQUENCIES) | ||
809 | && (j < sizeof(adapter->region_channel) | ||
810 | / sizeof(adapter->region_channel[0])); j++) { | ||
811 | cfp = adapter->region_channel[j].CFP; | ||
812 | for (i = 0; (range->num_frequency < IW_MAX_FREQUENCIES) | ||
813 | && adapter->region_channel[j].valid | ||
814 | && cfp | ||
815 | && (i < adapter->region_channel[j].nrcfp); i++) { | ||
816 | range->freq[range->num_frequency].i = | ||
817 | (long)cfp->channel; | ||
818 | range->freq[range->num_frequency].m = | ||
819 | (long)cfp->freq * 100000; | ||
820 | range->freq[range->num_frequency].e = 1; | ||
821 | cfp++; | ||
822 | range->num_frequency++; | ||
823 | } | ||
824 | } | ||
825 | } | ||
826 | |||
827 | lbs_pr_debug(1, "IW_MAX_FREQUENCIES=%d num_frequency=%d\n", | ||
828 | IW_MAX_FREQUENCIES, range->num_frequency); | ||
829 | |||
830 | range->num_channels = range->num_frequency; | ||
831 | |||
832 | sort_channels(&range->freq[0], range->num_frequency); | ||
833 | |||
834 | /* | ||
835 | * Set an indication of the max TCP throughput in bit/s that we can | ||
836 | * expect using this interface | ||
837 | */ | ||
838 | if (i > 2) | ||
839 | range->throughput = 5000 * 1000; | ||
840 | else | ||
841 | range->throughput = 1500 * 1000; | ||
842 | |||
843 | range->min_rts = MRVDRV_RTS_MIN_VALUE; | ||
844 | range->max_rts = MRVDRV_RTS_MAX_VALUE; | ||
845 | range->min_frag = MRVDRV_FRAG_MIN_VALUE; | ||
846 | range->max_frag = MRVDRV_FRAG_MAX_VALUE; | ||
847 | |||
848 | range->encoding_size[0] = 5; | ||
849 | range->encoding_size[1] = 13; | ||
850 | range->num_encoding_sizes = 2; | ||
851 | range->max_encoding_tokens = 4; | ||
852 | |||
853 | range->min_pmp = 1000000; | ||
854 | range->max_pmp = 120000000; | ||
855 | range->min_pmt = 1000; | ||
856 | range->max_pmt = 1000000; | ||
857 | range->pmp_flags = IW_POWER_PERIOD; | ||
858 | range->pmt_flags = IW_POWER_TIMEOUT; | ||
859 | range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_ALL_R; | ||
860 | |||
861 | /* | ||
862 | * Minimum version we recommend | ||
863 | */ | ||
864 | range->we_version_source = 15; | ||
865 | |||
866 | /* | ||
867 | * Version we are compiled with | ||
868 | */ | ||
869 | range->we_version_compiled = WIRELESS_EXT; | ||
870 | |||
871 | range->retry_capa = IW_RETRY_LIMIT; | ||
872 | range->retry_flags = IW_RETRY_LIMIT | IW_RETRY_MAX; | ||
873 | |||
874 | range->min_retry = TX_RETRY_MIN; | ||
875 | range->max_retry = TX_RETRY_MAX; | ||
876 | |||
877 | /* | ||
878 | * Set the qual, level and noise range values | ||
879 | */ | ||
880 | range->max_qual.qual = 100; | ||
881 | range->max_qual.level = 0; | ||
882 | range->max_qual.noise = 0; | ||
883 | range->max_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
884 | |||
885 | range->avg_qual.qual = 70; | ||
886 | /* TODO: Find real 'good' to 'bad' threshold value for RSSI */ | ||
887 | range->avg_qual.level = 0; | ||
888 | range->avg_qual.noise = 0; | ||
889 | range->avg_qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
890 | |||
891 | range->sensitivity = 0; | ||
892 | |||
893 | /* | ||
894 | * Setup the supported power level ranges | ||
895 | */ | ||
896 | memset(range->txpower, 0, sizeof(range->txpower)); | ||
897 | range->txpower[0] = 5; | ||
898 | range->txpower[1] = 7; | ||
899 | range->txpower[2] = 9; | ||
900 | range->txpower[3] = 11; | ||
901 | range->txpower[4] = 13; | ||
902 | range->txpower[5] = 15; | ||
903 | range->txpower[6] = 17; | ||
904 | range->txpower[7] = 19; | ||
905 | |||
906 | range->num_txpower = 8; | ||
907 | range->txpower_capa = IW_TXPOW_DBM; | ||
908 | range->txpower_capa |= IW_TXPOW_RANGE; | ||
909 | |||
910 | range->event_capa[0] = (IW_EVENT_CAPA_K_0 | | ||
911 | IW_EVENT_CAPA_MASK(SIOCGIWAP) | | ||
912 | IW_EVENT_CAPA_MASK(SIOCGIWSCAN)); | ||
913 | range->event_capa[1] = IW_EVENT_CAPA_K_1; | ||
914 | |||
915 | if (adapter->fwcapinfo & FW_CAPINFO_WPA) { | ||
916 | range->enc_capa = IW_ENC_CAPA_WPA | ||
917 | | IW_ENC_CAPA_WPA2 | ||
918 | | IW_ENC_CAPA_CIPHER_TKIP | ||
919 | | IW_ENC_CAPA_CIPHER_CCMP; | ||
920 | } | ||
921 | |||
922 | LEAVE(); | ||
923 | return 0; | ||
924 | } | ||
925 | |||
926 | static int wlan_set_power(struct net_device *dev, struct iw_request_info *info, | ||
927 | struct iw_param *vwrq, char *extra) | ||
928 | { | ||
929 | wlan_private *priv = dev->priv; | ||
930 | wlan_adapter *adapter = priv->adapter; | ||
931 | |||
932 | ENTER(); | ||
933 | |||
934 | /* PS is currently supported only in Infrastructure mode | ||
935 | * Remove this check if it is to be supported in IBSS mode also | ||
936 | */ | ||
937 | |||
938 | if (vwrq->disabled) { | ||
939 | adapter->psmode = wlan802_11powermodecam; | ||
940 | if (adapter->psstate != PS_STATE_FULL_POWER) { | ||
941 | libertas_ps_wakeup(priv, cmd_option_waitforrsp); | ||
942 | } | ||
943 | |||
944 | return 0; | ||
945 | } | ||
946 | |||
947 | if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
948 | lbs_pr_debug(1, | ||
949 | "Setting power timeout command is not supported\n"); | ||
950 | return -EINVAL; | ||
951 | } else if ((vwrq->flags & IW_POWER_TYPE) == IW_POWER_PERIOD) { | ||
952 | lbs_pr_debug(1, "Setting power period command is not supported\n"); | ||
953 | return -EINVAL; | ||
954 | } | ||
955 | |||
956 | if (adapter->psmode != wlan802_11powermodecam) { | ||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | adapter->psmode = wlan802_11powermodemax_psp; | ||
961 | |||
962 | if (adapter->connect_status == libertas_connected) { | ||
963 | libertas_ps_sleep(priv, cmd_option_waitforrsp); | ||
964 | } | ||
965 | |||
966 | LEAVE(); | ||
967 | return 0; | ||
968 | } | ||
969 | |||
970 | static int wlan_get_power(struct net_device *dev, struct iw_request_info *info, | ||
971 | struct iw_param *vwrq, char *extra) | ||
972 | { | ||
973 | wlan_private *priv = dev->priv; | ||
974 | wlan_adapter *adapter = priv->adapter; | ||
975 | int mode; | ||
976 | |||
977 | ENTER(); | ||
978 | |||
979 | mode = adapter->psmode; | ||
980 | |||
981 | if ((vwrq->disabled = (mode == wlan802_11powermodecam)) | ||
982 | || adapter->connect_status == libertas_disconnected) { | ||
983 | LEAVE(); | ||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | vwrq->value = 0; | ||
988 | |||
989 | LEAVE(); | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | /* | ||
994 | * iwpriv settable callbacks | ||
995 | */ | ||
996 | |||
997 | static const iw_handler wlan_private_handler[] = { | ||
998 | NULL, /* SIOCIWFIRSTPRIV */ | ||
999 | }; | ||
1000 | |||
1001 | static const struct iw_priv_args wlan_private_args[] = { | ||
1002 | /* | ||
1003 | * { cmd, set_args, get_args, name } | ||
1004 | */ | ||
1005 | { | ||
1006 | WLANSCAN_TYPE, | ||
1007 | IW_PRIV_TYPE_CHAR | 8, | ||
1008 | IW_PRIV_TYPE_CHAR | 8, | ||
1009 | "scantype"}, | ||
1010 | |||
1011 | { | ||
1012 | WLAN_SETINT_GETINT, | ||
1013 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1014 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1015 | ""}, | ||
1016 | { | ||
1017 | WLANNF, | ||
1018 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1019 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1020 | "getNF"}, | ||
1021 | { | ||
1022 | WLANRSSI, | ||
1023 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1024 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1025 | "getRSSI"}, | ||
1026 | { | ||
1027 | WLANENABLE11D, | ||
1028 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1029 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1030 | "enable11d"}, | ||
1031 | { | ||
1032 | WLANADHOCGRATE, | ||
1033 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1034 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1035 | "adhocgrate"}, | ||
1036 | |||
1037 | { | ||
1038 | WLAN_SUBCMD_SET_PRESCAN, | ||
1039 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1040 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1041 | "prescan"}, | ||
1042 | { | ||
1043 | WLAN_SETONEINT_GETONEINT, | ||
1044 | IW_PRIV_TYPE_INT | 1, | ||
1045 | IW_PRIV_TYPE_INT | 1, | ||
1046 | ""}, | ||
1047 | { | ||
1048 | WLAN_BEACON_INTERVAL, | ||
1049 | IW_PRIV_TYPE_INT | 1, | ||
1050 | IW_PRIV_TYPE_INT | 1, | ||
1051 | "bcninterval"}, | ||
1052 | { | ||
1053 | WLAN_LISTENINTRVL, | ||
1054 | IW_PRIV_TYPE_INT | 1, | ||
1055 | IW_PRIV_TYPE_INT | 1, | ||
1056 | "lolisteninter"}, | ||
1057 | { | ||
1058 | WLAN_TXCONTROL, | ||
1059 | IW_PRIV_TYPE_INT | 1, | ||
1060 | IW_PRIV_TYPE_INT | 1, | ||
1061 | "txcontrol"}, | ||
1062 | { | ||
1063 | WLAN_NULLPKTINTERVAL, | ||
1064 | IW_PRIV_TYPE_INT | 1, | ||
1065 | IW_PRIV_TYPE_INT | 1, | ||
1066 | "psnullinterval"}, | ||
1067 | /* Using iwpriv sub-command feature */ | ||
1068 | { | ||
1069 | WLAN_SETONEINT_GETNONE, /* IOCTL: 24 */ | ||
1070 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1071 | IW_PRIV_TYPE_NONE, | ||
1072 | ""}, | ||
1073 | |||
1074 | { | ||
1075 | WLAN_SUBCMD_SETRXANTENNA, | ||
1076 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1077 | IW_PRIV_TYPE_NONE, | ||
1078 | "setrxant"}, | ||
1079 | { | ||
1080 | WLAN_SUBCMD_SETTXANTENNA, | ||
1081 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1082 | IW_PRIV_TYPE_NONE, | ||
1083 | "settxant"}, | ||
1084 | { | ||
1085 | WLANSETAUTHALG, | ||
1086 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1087 | IW_PRIV_TYPE_NONE, | ||
1088 | "authalgs", | ||
1089 | }, | ||
1090 | { | ||
1091 | WLANSET8021XAUTHALG, | ||
1092 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1093 | IW_PRIV_TYPE_NONE, | ||
1094 | "8021xauthalgs", | ||
1095 | }, | ||
1096 | { | ||
1097 | WLANSETENCRYPTIONMODE, | ||
1098 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1099 | IW_PRIV_TYPE_NONE, | ||
1100 | "encryptionmode", | ||
1101 | }, | ||
1102 | { | ||
1103 | WLANSETREGION, | ||
1104 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1105 | IW_PRIV_TYPE_NONE, | ||
1106 | "setregioncode"}, | ||
1107 | { | ||
1108 | WLAN_SET_LISTEN_INTERVAL, | ||
1109 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1110 | IW_PRIV_TYPE_NONE, | ||
1111 | "setlisteninter"}, | ||
1112 | { | ||
1113 | WLAN_SET_MULTIPLE_DTIM, | ||
1114 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1115 | IW_PRIV_TYPE_NONE, | ||
1116 | "setmultipledtim"}, | ||
1117 | { | ||
1118 | WLAN_SET_ATIM_WINDOW, | ||
1119 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1120 | IW_PRIV_TYPE_NONE, | ||
1121 | "atimwindow"}, | ||
1122 | { | ||
1123 | WLANSETBCNAVG, | ||
1124 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1125 | IW_PRIV_TYPE_NONE, | ||
1126 | "setbcnavg"}, | ||
1127 | { | ||
1128 | WLANSETDATAAVG, | ||
1129 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1130 | IW_PRIV_TYPE_NONE, | ||
1131 | "setdataavg"}, | ||
1132 | { | ||
1133 | WLAN_SET_LINKMODE, | ||
1134 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1135 | IW_PRIV_TYPE_NONE, | ||
1136 | "linkmode"}, | ||
1137 | { | ||
1138 | WLAN_SET_RADIOMODE, | ||
1139 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1140 | IW_PRIV_TYPE_NONE, | ||
1141 | "radiomode"}, | ||
1142 | { | ||
1143 | WLAN_SET_DEBUGMODE, | ||
1144 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1145 | IW_PRIV_TYPE_NONE, | ||
1146 | "debugmode"}, | ||
1147 | { | ||
1148 | WLAN_SUBCMD_MESH_SET_TTL, | ||
1149 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1150 | IW_PRIV_TYPE_NONE, | ||
1151 | "mesh_set_ttl"}, | ||
1152 | { | ||
1153 | WLAN_SETNONE_GETONEINT, | ||
1154 | IW_PRIV_TYPE_NONE, | ||
1155 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1156 | ""}, | ||
1157 | { | ||
1158 | WLANGETREGION, | ||
1159 | IW_PRIV_TYPE_NONE, | ||
1160 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1161 | "getregioncode"}, | ||
1162 | { | ||
1163 | WLAN_GET_LISTEN_INTERVAL, | ||
1164 | IW_PRIV_TYPE_NONE, | ||
1165 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1166 | "getlisteninter"}, | ||
1167 | { | ||
1168 | WLAN_GET_MULTIPLE_DTIM, | ||
1169 | IW_PRIV_TYPE_NONE, | ||
1170 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1171 | "getmultipledtim"}, | ||
1172 | { | ||
1173 | WLAN_GET_TX_RATE, | ||
1174 | IW_PRIV_TYPE_NONE, | ||
1175 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1176 | "gettxrate"}, | ||
1177 | { | ||
1178 | WLANGETBCNAVG, | ||
1179 | IW_PRIV_TYPE_NONE, | ||
1180 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1181 | "getbcnavg"}, | ||
1182 | { | ||
1183 | WLAN_GET_LINKMODE, | ||
1184 | IW_PRIV_TYPE_NONE, | ||
1185 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1186 | "get_linkmode"}, | ||
1187 | { | ||
1188 | WLAN_GET_RADIOMODE, | ||
1189 | IW_PRIV_TYPE_NONE, | ||
1190 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1191 | "get_radiomode"}, | ||
1192 | { | ||
1193 | WLAN_GET_DEBUGMODE, | ||
1194 | IW_PRIV_TYPE_NONE, | ||
1195 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1196 | "get_debugmode"}, | ||
1197 | { | ||
1198 | WLAN_SUBCMD_FWT_CLEANUP, | ||
1199 | IW_PRIV_TYPE_NONE, | ||
1200 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1201 | "fwt_cleanup"}, | ||
1202 | { | ||
1203 | WLAN_SUBCMD_FWT_TIME, | ||
1204 | IW_PRIV_TYPE_NONE, | ||
1205 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1206 | "fwt_time"}, | ||
1207 | { | ||
1208 | WLAN_SUBCMD_MESH_GET_TTL, | ||
1209 | IW_PRIV_TYPE_NONE, | ||
1210 | IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1211 | "mesh_get_ttl"}, | ||
1212 | { | ||
1213 | WLAN_SETNONE_GETTWELVE_CHAR, | ||
1214 | IW_PRIV_TYPE_NONE, | ||
1215 | IW_PRIV_TYPE_CHAR | 12, | ||
1216 | ""}, | ||
1217 | { | ||
1218 | WLAN_SUBCMD_GETRXANTENNA, | ||
1219 | IW_PRIV_TYPE_NONE, | ||
1220 | IW_PRIV_TYPE_CHAR | 12, | ||
1221 | "getrxant"}, | ||
1222 | { | ||
1223 | WLAN_SUBCMD_GETTXANTENNA, | ||
1224 | IW_PRIV_TYPE_NONE, | ||
1225 | IW_PRIV_TYPE_CHAR | 12, | ||
1226 | "gettxant"}, | ||
1227 | { | ||
1228 | WLAN_GET_TSF, | ||
1229 | IW_PRIV_TYPE_NONE, | ||
1230 | IW_PRIV_TYPE_CHAR | 12, | ||
1231 | "gettsf"}, | ||
1232 | { | ||
1233 | WLAN_SETNONE_GETNONE, | ||
1234 | IW_PRIV_TYPE_NONE, | ||
1235 | IW_PRIV_TYPE_NONE, | ||
1236 | ""}, | ||
1237 | { | ||
1238 | WLANDEAUTH, | ||
1239 | IW_PRIV_TYPE_NONE, | ||
1240 | IW_PRIV_TYPE_NONE, | ||
1241 | "deauth"}, | ||
1242 | { | ||
1243 | WLANADHOCSTOP, | ||
1244 | IW_PRIV_TYPE_NONE, | ||
1245 | IW_PRIV_TYPE_NONE, | ||
1246 | "adhocstop"}, | ||
1247 | { | ||
1248 | WLANRADIOON, | ||
1249 | IW_PRIV_TYPE_NONE, | ||
1250 | IW_PRIV_TYPE_NONE, | ||
1251 | "radioon"}, | ||
1252 | { | ||
1253 | WLANRADIOOFF, | ||
1254 | IW_PRIV_TYPE_NONE, | ||
1255 | IW_PRIV_TYPE_NONE, | ||
1256 | "radiooff"}, | ||
1257 | { | ||
1258 | WLANWLANIDLEON, | ||
1259 | IW_PRIV_TYPE_NONE, | ||
1260 | IW_PRIV_TYPE_NONE, | ||
1261 | "wlanidle-on"}, | ||
1262 | { | ||
1263 | WLANWLANIDLEOFF, | ||
1264 | IW_PRIV_TYPE_NONE, | ||
1265 | IW_PRIV_TYPE_NONE, | ||
1266 | "wlanidle-off"}, | ||
1267 | { | ||
1268 | WLAN_SUBCMD_FWT_RESET, | ||
1269 | IW_PRIV_TYPE_NONE, | ||
1270 | IW_PRIV_TYPE_NONE, | ||
1271 | "fwt_reset"}, | ||
1272 | { | ||
1273 | WLAN_SUBCMD_BT_RESET, | ||
1274 | IW_PRIV_TYPE_NONE, | ||
1275 | IW_PRIV_TYPE_NONE, | ||
1276 | "bt_reset"}, | ||
1277 | { | ||
1278 | WLAN_SET128CHAR_GET128CHAR, | ||
1279 | IW_PRIV_TYPE_CHAR | 128, | ||
1280 | IW_PRIV_TYPE_CHAR | 128, | ||
1281 | ""}, | ||
1282 | /* BT Management */ | ||
1283 | { | ||
1284 | WLAN_SUBCMD_BT_ADD, | ||
1285 | IW_PRIV_TYPE_CHAR | 128, | ||
1286 | IW_PRIV_TYPE_CHAR | 128, | ||
1287 | "bt_add"}, | ||
1288 | { | ||
1289 | WLAN_SUBCMD_BT_DEL, | ||
1290 | IW_PRIV_TYPE_CHAR | 128, | ||
1291 | IW_PRIV_TYPE_CHAR | 128, | ||
1292 | "bt_del"}, | ||
1293 | { | ||
1294 | WLAN_SUBCMD_BT_LIST, | ||
1295 | IW_PRIV_TYPE_CHAR | 128, | ||
1296 | IW_PRIV_TYPE_CHAR | 128, | ||
1297 | "bt_list"}, | ||
1298 | /* FWT Management */ | ||
1299 | { | ||
1300 | WLAN_SUBCMD_FWT_ADD, | ||
1301 | IW_PRIV_TYPE_CHAR | 128, | ||
1302 | IW_PRIV_TYPE_CHAR | 128, | ||
1303 | "fwt_add"}, | ||
1304 | { | ||
1305 | WLAN_SUBCMD_FWT_DEL, | ||
1306 | IW_PRIV_TYPE_CHAR | 128, | ||
1307 | IW_PRIV_TYPE_CHAR | 128, | ||
1308 | "fwt_del"}, | ||
1309 | { | ||
1310 | WLAN_SUBCMD_FWT_LOOKUP, | ||
1311 | IW_PRIV_TYPE_CHAR | 128, | ||
1312 | IW_PRIV_TYPE_CHAR | 128, | ||
1313 | "fwt_lookup"}, | ||
1314 | { | ||
1315 | WLAN_SUBCMD_FWT_LIST_NEIGHBOR, | ||
1316 | IW_PRIV_TYPE_CHAR | 128, | ||
1317 | IW_PRIV_TYPE_CHAR | 128, | ||
1318 | "fwt_list_neigh"}, | ||
1319 | { | ||
1320 | WLAN_SUBCMD_FWT_LIST, | ||
1321 | IW_PRIV_TYPE_CHAR | 128, | ||
1322 | IW_PRIV_TYPE_CHAR | 128, | ||
1323 | "fwt_list"}, | ||
1324 | { | ||
1325 | WLAN_SUBCMD_FWT_LIST_ROUTE, | ||
1326 | IW_PRIV_TYPE_CHAR | 128, | ||
1327 | IW_PRIV_TYPE_CHAR | 128, | ||
1328 | "fwt_list_route"}, | ||
1329 | { | ||
1330 | WLANSCAN_MODE, | ||
1331 | IW_PRIV_TYPE_CHAR | 128, | ||
1332 | IW_PRIV_TYPE_CHAR | 128, | ||
1333 | "scanmode"}, | ||
1334 | { | ||
1335 | WLAN_GET_ADHOC_STATUS, | ||
1336 | IW_PRIV_TYPE_CHAR | 128, | ||
1337 | IW_PRIV_TYPE_CHAR | 128, | ||
1338 | "getadhocstatus"}, | ||
1339 | { | ||
1340 | WLAN_SETNONE_GETWORDCHAR, | ||
1341 | IW_PRIV_TYPE_NONE, | ||
1342 | IW_PRIV_TYPE_CHAR | 128, | ||
1343 | ""}, | ||
1344 | { | ||
1345 | WLANSETWPAIE, | ||
1346 | IW_PRIV_TYPE_CHAR | IW_PRIV_SIZE_FIXED | 24, | ||
1347 | IW_PRIV_TYPE_NONE, | ||
1348 | "setwpaie"}, | ||
1349 | { | ||
1350 | WLANGETLOG, | ||
1351 | IW_PRIV_TYPE_NONE, | ||
1352 | IW_PRIV_TYPE_CHAR | GETLOG_BUFSIZE, | ||
1353 | "getlog"}, | ||
1354 | { | ||
1355 | WLAN_SET_GET_SIXTEEN_INT, | ||
1356 | IW_PRIV_TYPE_INT | 16, | ||
1357 | IW_PRIV_TYPE_INT | 16, | ||
1358 | ""}, | ||
1359 | { | ||
1360 | WLAN_TPCCFG, | ||
1361 | IW_PRIV_TYPE_INT | 16, | ||
1362 | IW_PRIV_TYPE_INT | 16, | ||
1363 | "tpccfg"}, | ||
1364 | { | ||
1365 | WLAN_POWERCFG, | ||
1366 | IW_PRIV_TYPE_INT | 16, | ||
1367 | IW_PRIV_TYPE_INT | 16, | ||
1368 | "powercfg"}, | ||
1369 | { | ||
1370 | WLAN_AUTO_FREQ_SET, | ||
1371 | IW_PRIV_TYPE_INT | 16, | ||
1372 | IW_PRIV_TYPE_INT | 16, | ||
1373 | "setafc"}, | ||
1374 | { | ||
1375 | WLAN_AUTO_FREQ_GET, | ||
1376 | IW_PRIV_TYPE_INT | 16, | ||
1377 | IW_PRIV_TYPE_INT | 16, | ||
1378 | "getafc"}, | ||
1379 | { | ||
1380 | WLAN_SCANPROBES, | ||
1381 | IW_PRIV_TYPE_INT | 16, | ||
1382 | IW_PRIV_TYPE_INT | 16, | ||
1383 | "scanprobes"}, | ||
1384 | { | ||
1385 | WLAN_LED_GPIO_CTRL, | ||
1386 | IW_PRIV_TYPE_INT | 16, | ||
1387 | IW_PRIV_TYPE_INT | 16, | ||
1388 | "ledgpio"}, | ||
1389 | { | ||
1390 | WLAN_ADAPT_RATESET, | ||
1391 | IW_PRIV_TYPE_INT | 16, | ||
1392 | IW_PRIV_TYPE_INT | 16, | ||
1393 | "rateadapt"}, | ||
1394 | { | ||
1395 | WLAN_INACTIVITY_TIMEOUT, | ||
1396 | IW_PRIV_TYPE_INT | 16, | ||
1397 | IW_PRIV_TYPE_INT | 16, | ||
1398 | "inactivityto"}, | ||
1399 | { | ||
1400 | WLANSNR, | ||
1401 | IW_PRIV_TYPE_INT | 16, | ||
1402 | IW_PRIV_TYPE_INT | 16, | ||
1403 | "getSNR"}, | ||
1404 | { | ||
1405 | WLAN_GET_RATE, | ||
1406 | IW_PRIV_TYPE_INT | 16, | ||
1407 | IW_PRIV_TYPE_INT | 16, | ||
1408 | "getrate"}, | ||
1409 | { | ||
1410 | WLAN_GET_RXINFO, | ||
1411 | IW_PRIV_TYPE_INT | 16, | ||
1412 | IW_PRIV_TYPE_INT | 16, | ||
1413 | "getrxinfo"}, | ||
1414 | }; | ||
1415 | |||
1416 | static struct iw_statistics *wlan_get_wireless_stats(struct net_device *dev) | ||
1417 | { | ||
1418 | enum { | ||
1419 | POOR = 30, | ||
1420 | FAIR = 60, | ||
1421 | GOOD = 80, | ||
1422 | VERY_GOOD = 90, | ||
1423 | EXCELLENT = 95, | ||
1424 | PERFECT = 100 | ||
1425 | }; | ||
1426 | wlan_private *priv = dev->priv; | ||
1427 | wlan_adapter *adapter = priv->adapter; | ||
1428 | u32 rssi_qual; | ||
1429 | u32 tx_qual; | ||
1430 | u32 quality = 0; | ||
1431 | int stats_valid = 0; | ||
1432 | u8 rssi; | ||
1433 | u32 tx_retries; | ||
1434 | |||
1435 | ENTER(); | ||
1436 | |||
1437 | priv->wstats.status = adapter->inframode; | ||
1438 | |||
1439 | /* If we're not associated, all quality values are meaningless */ | ||
1440 | if (adapter->connect_status != libertas_connected) | ||
1441 | goto out; | ||
1442 | |||
1443 | /* Quality by RSSI */ | ||
1444 | priv->wstats.qual.level = | ||
1445 | CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], | ||
1446 | adapter->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
1447 | |||
1448 | if (adapter->NF[TYPE_BEACON][TYPE_NOAVG] == 0) { | ||
1449 | priv->wstats.qual.noise = MRVDRV_NF_DEFAULT_SCAN_VALUE; | ||
1450 | } else { | ||
1451 | priv->wstats.qual.noise = | ||
1452 | CAL_NF(adapter->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
1453 | } | ||
1454 | |||
1455 | lbs_pr_debug(1, "Signal Level = %#x\n", priv->wstats.qual.level); | ||
1456 | lbs_pr_debug(1, "Noise = %#x\n", priv->wstats.qual.noise); | ||
1457 | |||
1458 | rssi = priv->wstats.qual.level - priv->wstats.qual.noise; | ||
1459 | if (rssi < 15) | ||
1460 | rssi_qual = rssi * POOR / 10; | ||
1461 | else if (rssi < 20) | ||
1462 | rssi_qual = (rssi - 15) * (FAIR - POOR) / 5 + POOR; | ||
1463 | else if (rssi < 30) | ||
1464 | rssi_qual = (rssi - 20) * (GOOD - FAIR) / 5 + FAIR; | ||
1465 | else if (rssi < 40) | ||
1466 | rssi_qual = (rssi - 30) * (VERY_GOOD - GOOD) / | ||
1467 | 10 + GOOD; | ||
1468 | else | ||
1469 | rssi_qual = (rssi - 40) * (PERFECT - VERY_GOOD) / | ||
1470 | 10 + VERY_GOOD; | ||
1471 | quality = rssi_qual; | ||
1472 | |||
1473 | /* Quality by TX errors */ | ||
1474 | priv->wstats.discard.retries = priv->stats.tx_errors; | ||
1475 | |||
1476 | tx_retries = adapter->logmsg.retry; | ||
1477 | |||
1478 | if (tx_retries > 75) | ||
1479 | tx_qual = (90 - tx_retries) * POOR / 15; | ||
1480 | else if (tx_retries > 70) | ||
1481 | tx_qual = (75 - tx_retries) * (FAIR - POOR) / 5 + POOR; | ||
1482 | else if (tx_retries > 65) | ||
1483 | tx_qual = (70 - tx_retries) * (GOOD - FAIR) / 5 + FAIR; | ||
1484 | else if (tx_retries > 50) | ||
1485 | tx_qual = (65 - tx_retries) * (VERY_GOOD - GOOD) / | ||
1486 | 15 + GOOD; | ||
1487 | else | ||
1488 | tx_qual = (50 - tx_retries) * | ||
1489 | (PERFECT - VERY_GOOD) / 50 + VERY_GOOD; | ||
1490 | quality = min(quality, tx_qual); | ||
1491 | |||
1492 | priv->wstats.discard.code = adapter->logmsg.wepundecryptable; | ||
1493 | priv->wstats.discard.fragment = adapter->logmsg.fcserror; | ||
1494 | priv->wstats.discard.retries = tx_retries; | ||
1495 | priv->wstats.discard.misc = adapter->logmsg.ackfailure; | ||
1496 | |||
1497 | /* Calculate quality */ | ||
1498 | priv->wstats.qual.qual = max(quality, (u32)100); | ||
1499 | priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
1500 | stats_valid = 1; | ||
1501 | |||
1502 | /* update stats asynchronously for future calls */ | ||
1503 | libertas_prepare_and_send_command(priv, cmd_802_11_rssi, 0, | ||
1504 | 0, 0, NULL); | ||
1505 | libertas_prepare_and_send_command(priv, cmd_802_11_get_log, 0, | ||
1506 | 0, 0, NULL); | ||
1507 | out: | ||
1508 | if (!stats_valid) { | ||
1509 | priv->wstats.miss.beacon = 0; | ||
1510 | priv->wstats.discard.retries = 0; | ||
1511 | priv->wstats.qual.qual = 0; | ||
1512 | priv->wstats.qual.level = 0; | ||
1513 | priv->wstats.qual.noise = 0; | ||
1514 | priv->wstats.qual.updated = IW_QUAL_ALL_UPDATED; | ||
1515 | priv->wstats.qual.updated |= IW_QUAL_NOISE_INVALID | | ||
1516 | IW_QUAL_QUAL_INVALID | IW_QUAL_LEVEL_INVALID; | ||
1517 | } | ||
1518 | |||
1519 | LEAVE (); | ||
1520 | return &priv->wstats; | ||
1521 | |||
1522 | |||
1523 | } | ||
1524 | |||
1525 | static int wlan_set_freq(struct net_device *dev, struct iw_request_info *info, | ||
1526 | struct iw_freq *fwrq, char *extra) | ||
1527 | { | ||
1528 | int ret = 0; | ||
1529 | wlan_private *priv = dev->priv; | ||
1530 | wlan_adapter *adapter = priv->adapter; | ||
1531 | int rc = -EINPROGRESS; /* Call commit handler */ | ||
1532 | struct chan_freq_power *cfp; | ||
1533 | |||
1534 | ENTER(); | ||
1535 | |||
1536 | /* | ||
1537 | * If setting by frequency, convert to a channel | ||
1538 | */ | ||
1539 | if (fwrq->e == 1) { | ||
1540 | |||
1541 | long f = fwrq->m / 100000; | ||
1542 | int c = 0; | ||
1543 | |||
1544 | cfp = find_cfp_by_band_and_freq(adapter, 0, f); | ||
1545 | if (!cfp) { | ||
1546 | lbs_pr_debug(1, "Invalid freq=%ld\n", f); | ||
1547 | return -EINVAL; | ||
1548 | } | ||
1549 | |||
1550 | c = (int)cfp->channel; | ||
1551 | |||
1552 | if (c < 0) | ||
1553 | return -EINVAL; | ||
1554 | |||
1555 | fwrq->e = 0; | ||
1556 | fwrq->m = c; | ||
1557 | } | ||
1558 | |||
1559 | /* | ||
1560 | * Setting by channel number | ||
1561 | */ | ||
1562 | if (fwrq->m > 1000 || fwrq->e > 0) { | ||
1563 | rc = -EOPNOTSUPP; | ||
1564 | } else { | ||
1565 | int channel = fwrq->m; | ||
1566 | |||
1567 | cfp = libertas_find_cfp_by_band_and_channel(adapter, 0, channel); | ||
1568 | if (!cfp) { | ||
1569 | rc = -EINVAL; | ||
1570 | } else { | ||
1571 | if (adapter->inframode == wlan802_11ibss) { | ||
1572 | rc = changeadhocchannel(priv, channel); | ||
1573 | /* If station is WEP enabled, send the | ||
1574 | * command to set WEP in firmware | ||
1575 | */ | ||
1576 | if (adapter->secinfo.WEPstatus == | ||
1577 | wlan802_11WEPenabled) { | ||
1578 | lbs_pr_debug(1, "set_freq: WEP enabled\n"); | ||
1579 | ret = libertas_prepare_and_send_command(priv, | ||
1580 | cmd_802_11_set_wep, | ||
1581 | cmd_act_add, | ||
1582 | cmd_option_waitforrsp, | ||
1583 | 0, | ||
1584 | NULL); | ||
1585 | |||
1586 | if (ret) { | ||
1587 | LEAVE(); | ||
1588 | return ret; | ||
1589 | } | ||
1590 | |||
1591 | adapter->currentpacketfilter |= | ||
1592 | cmd_act_mac_wep_enable; | ||
1593 | |||
1594 | libertas_set_mac_packet_filter(priv); | ||
1595 | } | ||
1596 | } else { | ||
1597 | rc = -EOPNOTSUPP; | ||
1598 | } | ||
1599 | } | ||
1600 | } | ||
1601 | |||
1602 | LEAVE(); | ||
1603 | return rc; | ||
1604 | } | ||
1605 | |||
1606 | /** | ||
1607 | * @brief use index to get the data rate | ||
1608 | * | ||
1609 | * @param index The index of data rate | ||
1610 | * @return data rate or 0 | ||
1611 | */ | ||
1612 | u32 libertas_index_to_data_rate(u8 index) | ||
1613 | { | ||
1614 | if (index >= sizeof(libertas_wlan_data_rates)) | ||
1615 | index = 0; | ||
1616 | |||
1617 | return libertas_wlan_data_rates[index]; | ||
1618 | } | ||
1619 | |||
1620 | /** | ||
1621 | * @brief use rate to get the index | ||
1622 | * | ||
1623 | * @param rate data rate | ||
1624 | * @return index or 0 | ||
1625 | */ | ||
1626 | u8 libertas_data_rate_to_index(u32 rate) | ||
1627 | { | ||
1628 | u8 *ptr; | ||
1629 | |||
1630 | if (rate) | ||
1631 | if ((ptr = memchr(libertas_wlan_data_rates, (u8) rate, | ||
1632 | sizeof(libertas_wlan_data_rates)))) | ||
1633 | return (ptr - libertas_wlan_data_rates); | ||
1634 | |||
1635 | return 0; | ||
1636 | } | ||
1637 | |||
1638 | static int wlan_set_rate(struct net_device *dev, struct iw_request_info *info, | ||
1639 | struct iw_param *vwrq, char *extra) | ||
1640 | { | ||
1641 | wlan_private *priv = dev->priv; | ||
1642 | wlan_adapter *adapter = priv->adapter; | ||
1643 | u32 data_rate; | ||
1644 | u16 action; | ||
1645 | int ret = 0; | ||
1646 | u8 rates[WLAN_SUPPORTED_RATES]; | ||
1647 | u8 *rate; | ||
1648 | |||
1649 | ENTER(); | ||
1650 | |||
1651 | lbs_pr_debug(1, "Vwrq->value = %d\n", vwrq->value); | ||
1652 | |||
1653 | if (vwrq->value == -1) { | ||
1654 | action = cmd_act_set_tx_auto; // Auto | ||
1655 | adapter->is_datarate_auto = 1; | ||
1656 | adapter->datarate = 0; | ||
1657 | } else { | ||
1658 | if (vwrq->value % 100000) { | ||
1659 | return -EINVAL; | ||
1660 | } | ||
1661 | |||
1662 | data_rate = vwrq->value / 500000; | ||
1663 | |||
1664 | memset(rates, 0, sizeof(rates)); | ||
1665 | get_active_data_rates(adapter, rates); | ||
1666 | rate = rates; | ||
1667 | while (*rate) { | ||
1668 | lbs_pr_debug(1, "Rate=0x%X Wanted=0x%X\n", *rate, | ||
1669 | data_rate); | ||
1670 | if ((*rate & 0x7f) == (data_rate & 0x7f)) | ||
1671 | break; | ||
1672 | rate++; | ||
1673 | } | ||
1674 | if (!*rate) { | ||
1675 | lbs_pr_alert( "The fixed data rate 0x%X is out " | ||
1676 | "of range.\n", data_rate); | ||
1677 | return -EINVAL; | ||
1678 | } | ||
1679 | |||
1680 | adapter->datarate = data_rate; | ||
1681 | action = cmd_act_set_tx_fix_rate; | ||
1682 | adapter->is_datarate_auto = 0; | ||
1683 | } | ||
1684 | |||
1685 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_data_rate, | ||
1686 | action, cmd_option_waitforrsp, 0, NULL); | ||
1687 | |||
1688 | LEAVE(); | ||
1689 | return ret; | ||
1690 | } | ||
1691 | |||
1692 | static int wlan_get_rate(struct net_device *dev, struct iw_request_info *info, | ||
1693 | struct iw_param *vwrq, char *extra) | ||
1694 | { | ||
1695 | wlan_private *priv = dev->priv; | ||
1696 | wlan_adapter *adapter = priv->adapter; | ||
1697 | |||
1698 | ENTER(); | ||
1699 | |||
1700 | if (adapter->is_datarate_auto) { | ||
1701 | vwrq->fixed = 0; | ||
1702 | } else { | ||
1703 | vwrq->fixed = 1; | ||
1704 | } | ||
1705 | |||
1706 | vwrq->value = adapter->datarate * 500000; | ||
1707 | |||
1708 | LEAVE(); | ||
1709 | return 0; | ||
1710 | } | ||
1711 | |||
1712 | static int wlan_set_mode(struct net_device *dev, | ||
1713 | struct iw_request_info *info, u32 * uwrq, char *extra) | ||
1714 | { | ||
1715 | int ret = 0; | ||
1716 | wlan_private *priv = dev->priv; | ||
1717 | wlan_adapter *adapter = priv->adapter; | ||
1718 | struct assoc_request * assoc_req; | ||
1719 | enum WLAN_802_11_NETWORK_INFRASTRUCTURE new_mode; | ||
1720 | |||
1721 | ENTER(); | ||
1722 | |||
1723 | switch (*uwrq) { | ||
1724 | case IW_MODE_ADHOC: | ||
1725 | lbs_pr_debug(1, "Wanted mode is ad-hoc: current datarate=%#x\n", | ||
1726 | adapter->datarate); | ||
1727 | new_mode = wlan802_11ibss; | ||
1728 | adapter->adhocchannel = DEFAULT_AD_HOC_CHANNEL; | ||
1729 | break; | ||
1730 | |||
1731 | case IW_MODE_INFRA: | ||
1732 | lbs_pr_debug(1, "Wanted mode is Infrastructure\n"); | ||
1733 | new_mode = wlan802_11infrastructure; | ||
1734 | break; | ||
1735 | |||
1736 | case IW_MODE_AUTO: | ||
1737 | lbs_pr_debug(1, "Wanted mode is Auto\n"); | ||
1738 | new_mode = wlan802_11autounknown; | ||
1739 | break; | ||
1740 | |||
1741 | default: | ||
1742 | lbs_pr_debug(1, "Wanted mode is Unknown: 0x%x\n", *uwrq); | ||
1743 | return -EINVAL; | ||
1744 | } | ||
1745 | |||
1746 | mutex_lock(&adapter->lock); | ||
1747 | assoc_req = wlan_get_association_request(adapter); | ||
1748 | if (!assoc_req) { | ||
1749 | ret = -ENOMEM; | ||
1750 | } else { | ||
1751 | assoc_req->mode = new_mode; | ||
1752 | } | ||
1753 | |||
1754 | if (ret == 0) { | ||
1755 | set_bit(ASSOC_FLAG_MODE, &assoc_req->flags); | ||
1756 | wlan_postpone_association_work(priv); | ||
1757 | } else { | ||
1758 | wlan_cancel_association_work(priv); | ||
1759 | } | ||
1760 | mutex_unlock(&adapter->lock); | ||
1761 | |||
1762 | LEAVE(); | ||
1763 | return ret; | ||
1764 | } | ||
1765 | |||
1766 | |||
1767 | /** | ||
1768 | * @brief Get Encryption key | ||
1769 | * | ||
1770 | * @param dev A pointer to net_device structure | ||
1771 | * @param info A pointer to iw_request_info structure | ||
1772 | * @param vwrq A pointer to iw_param structure | ||
1773 | * @param extra A pointer to extra data buf | ||
1774 | * @return 0 --success, otherwise fail | ||
1775 | */ | ||
1776 | static int wlan_get_encode(struct net_device *dev, | ||
1777 | struct iw_request_info *info, | ||
1778 | struct iw_point *dwrq, u8 * extra) | ||
1779 | { | ||
1780 | wlan_private *priv = dev->priv; | ||
1781 | wlan_adapter *adapter = priv->adapter; | ||
1782 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | ||
1783 | |||
1784 | ENTER(); | ||
1785 | |||
1786 | lbs_pr_debug(1, "flags=0x%x index=%d length=%d wep_tx_keyidx=%d\n", | ||
1787 | dwrq->flags, index, dwrq->length, adapter->wep_tx_keyidx); | ||
1788 | |||
1789 | dwrq->flags = 0; | ||
1790 | |||
1791 | /* Authentication method */ | ||
1792 | switch (adapter->secinfo.authmode) { | ||
1793 | case wlan802_11authmodeopen: | ||
1794 | dwrq->flags = IW_ENCODE_OPEN; | ||
1795 | break; | ||
1796 | |||
1797 | case wlan802_11authmodeshared: | ||
1798 | case wlan802_11authmodenetworkEAP: | ||
1799 | dwrq->flags = IW_ENCODE_RESTRICTED; | ||
1800 | break; | ||
1801 | default: | ||
1802 | dwrq->flags = IW_ENCODE_DISABLED | IW_ENCODE_OPEN; | ||
1803 | break; | ||
1804 | } | ||
1805 | |||
1806 | if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled) | ||
1807 | || adapter->secinfo.WPAenabled || adapter->secinfo.WPA2enabled) { | ||
1808 | dwrq->flags &= ~IW_ENCODE_DISABLED; | ||
1809 | } else { | ||
1810 | dwrq->flags |= IW_ENCODE_DISABLED; | ||
1811 | } | ||
1812 | |||
1813 | memset(extra, 0, 16); | ||
1814 | |||
1815 | mutex_lock(&adapter->lock); | ||
1816 | |||
1817 | /* Default to returning current transmit key */ | ||
1818 | if (index < 0) | ||
1819 | index = adapter->wep_tx_keyidx; | ||
1820 | |||
1821 | if ((adapter->wep_keys[index].len) && | ||
1822 | (adapter->secinfo.WEPstatus == wlan802_11WEPenabled)) { | ||
1823 | memcpy(extra, adapter->wep_keys[index].key, | ||
1824 | adapter->wep_keys[index].len); | ||
1825 | dwrq->length = adapter->wep_keys[index].len; | ||
1826 | |||
1827 | dwrq->flags |= (index + 1); | ||
1828 | /* Return WEP enabled */ | ||
1829 | dwrq->flags &= ~IW_ENCODE_DISABLED; | ||
1830 | } else if ((adapter->secinfo.WPAenabled) | ||
1831 | || (adapter->secinfo.WPA2enabled)) { | ||
1832 | /* return WPA enabled */ | ||
1833 | dwrq->flags &= ~IW_ENCODE_DISABLED; | ||
1834 | } else { | ||
1835 | dwrq->flags |= IW_ENCODE_DISABLED; | ||
1836 | } | ||
1837 | |||
1838 | mutex_unlock(&adapter->lock); | ||
1839 | |||
1840 | dwrq->flags |= IW_ENCODE_NOKEY; | ||
1841 | |||
1842 | lbs_pr_debug(1, "key:%02x:%02x:%02x:%02x:%02x:%02x keylen=%d\n", | ||
1843 | extra[0], extra[1], extra[2], | ||
1844 | extra[3], extra[4], extra[5], dwrq->length); | ||
1845 | |||
1846 | lbs_pr_debug(1, "Return flags=0x%x\n", dwrq->flags); | ||
1847 | |||
1848 | LEAVE(); | ||
1849 | return 0; | ||
1850 | } | ||
1851 | |||
1852 | /** | ||
1853 | * @brief Set Encryption key (internal) | ||
1854 | * | ||
1855 | * @param priv A pointer to private card structure | ||
1856 | * @param key_material A pointer to key material | ||
1857 | * @param key_length length of key material | ||
1858 | * @param index key index to set | ||
1859 | * @param set_tx_key Force set TX key (1 = yes, 0 = no) | ||
1860 | * @return 0 --success, otherwise fail | ||
1861 | */ | ||
1862 | static int wlan_set_wep_key(struct assoc_request *assoc_req, | ||
1863 | const char *key_material, | ||
1864 | u16 key_length, | ||
1865 | u16 index, | ||
1866 | int set_tx_key) | ||
1867 | { | ||
1868 | struct WLAN_802_11_KEY *pkey; | ||
1869 | |||
1870 | ENTER(); | ||
1871 | |||
1872 | /* Paranoid validation of key index */ | ||
1873 | if (index > 3) { | ||
1874 | LEAVE(); | ||
1875 | return -EINVAL; | ||
1876 | } | ||
1877 | |||
1878 | /* validate max key length */ | ||
1879 | if (key_length > KEY_LEN_WEP_104) { | ||
1880 | LEAVE(); | ||
1881 | return -EINVAL; | ||
1882 | } | ||
1883 | |||
1884 | pkey = &assoc_req->wep_keys[index]; | ||
1885 | |||
1886 | if (key_length > 0) { | ||
1887 | memset(pkey, 0, sizeof(struct WLAN_802_11_KEY)); | ||
1888 | pkey->type = KEY_TYPE_ID_WEP; | ||
1889 | |||
1890 | /* Standardize the key length */ | ||
1891 | pkey->len = (key_length > KEY_LEN_WEP_40) ? | ||
1892 | KEY_LEN_WEP_104 : KEY_LEN_WEP_40; | ||
1893 | memcpy(pkey->key, key_material, key_length); | ||
1894 | } | ||
1895 | |||
1896 | if (set_tx_key) { | ||
1897 | /* Ensure the chosen key is valid */ | ||
1898 | if (!pkey->len) { | ||
1899 | lbs_pr_debug(1, "key not set, so cannot enable it\n"); | ||
1900 | LEAVE(); | ||
1901 | return -EINVAL; | ||
1902 | } | ||
1903 | assoc_req->wep_tx_keyidx = index; | ||
1904 | } | ||
1905 | |||
1906 | assoc_req->secinfo.WEPstatus = wlan802_11WEPenabled; | ||
1907 | |||
1908 | LEAVE(); | ||
1909 | return 0; | ||
1910 | } | ||
1911 | |||
1912 | static int validate_key_index(u16 def_index, u16 raw_index, | ||
1913 | u16 *out_index, u16 *is_default) | ||
1914 | { | ||
1915 | if (!out_index || !is_default) | ||
1916 | return -EINVAL; | ||
1917 | |||
1918 | /* Verify index if present, otherwise use default TX key index */ | ||
1919 | if (raw_index > 0) { | ||
1920 | if (raw_index > 4) | ||
1921 | return -EINVAL; | ||
1922 | *out_index = raw_index - 1; | ||
1923 | } else { | ||
1924 | *out_index = def_index; | ||
1925 | *is_default = 1; | ||
1926 | } | ||
1927 | return 0; | ||
1928 | } | ||
1929 | |||
1930 | static void disable_wep(struct assoc_request *assoc_req) | ||
1931 | { | ||
1932 | int i; | ||
1933 | |||
1934 | /* Set Open System auth mode */ | ||
1935 | assoc_req->secinfo.authmode = wlan802_11authmodeopen; | ||
1936 | |||
1937 | /* Clear WEP keys and mark WEP as disabled */ | ||
1938 | assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; | ||
1939 | for (i = 0; i < 4; i++) | ||
1940 | assoc_req->wep_keys[i].len = 0; | ||
1941 | |||
1942 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
1943 | set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); | ||
1944 | } | ||
1945 | |||
1946 | /** | ||
1947 | * @brief Set Encryption key | ||
1948 | * | ||
1949 | * @param dev A pointer to net_device structure | ||
1950 | * @param info A pointer to iw_request_info structure | ||
1951 | * @param vwrq A pointer to iw_param structure | ||
1952 | * @param extra A pointer to extra data buf | ||
1953 | * @return 0 --success, otherwise fail | ||
1954 | */ | ||
1955 | static int wlan_set_encode(struct net_device *dev, | ||
1956 | struct iw_request_info *info, | ||
1957 | struct iw_point *dwrq, char *extra) | ||
1958 | { | ||
1959 | int ret = 0; | ||
1960 | wlan_private *priv = dev->priv; | ||
1961 | wlan_adapter *adapter = priv->adapter; | ||
1962 | struct assoc_request * assoc_req; | ||
1963 | u16 is_default = 0, index = 0, set_tx_key = 0; | ||
1964 | |||
1965 | ENTER(); | ||
1966 | |||
1967 | mutex_lock(&adapter->lock); | ||
1968 | assoc_req = wlan_get_association_request(adapter); | ||
1969 | if (!assoc_req) { | ||
1970 | ret = -ENOMEM; | ||
1971 | goto out; | ||
1972 | } | ||
1973 | |||
1974 | if (dwrq->flags & IW_ENCODE_DISABLED) { | ||
1975 | disable_wep (assoc_req); | ||
1976 | goto out; | ||
1977 | } | ||
1978 | |||
1979 | ret = validate_key_index(assoc_req->wep_tx_keyidx, | ||
1980 | (dwrq->flags & IW_ENCODE_INDEX), | ||
1981 | &index, &is_default); | ||
1982 | if (ret) { | ||
1983 | ret = -EINVAL; | ||
1984 | goto out; | ||
1985 | } | ||
1986 | |||
1987 | /* If WEP isn't enabled, or if there is no key data but a valid | ||
1988 | * index, set the TX key. | ||
1989 | */ | ||
1990 | if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled) | ||
1991 | || (dwrq->length == 0 && !is_default)) | ||
1992 | set_tx_key = 1; | ||
1993 | |||
1994 | ret = wlan_set_wep_key(assoc_req, extra, dwrq->length, index, set_tx_key); | ||
1995 | if (ret) | ||
1996 | goto out; | ||
1997 | |||
1998 | if (dwrq->length) | ||
1999 | set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); | ||
2000 | if (set_tx_key) | ||
2001 | set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); | ||
2002 | |||
2003 | if (dwrq->flags & IW_ENCODE_RESTRICTED) { | ||
2004 | assoc_req->secinfo.authmode = wlan802_11authmodeshared; | ||
2005 | } else if (dwrq->flags & IW_ENCODE_OPEN) { | ||
2006 | assoc_req->secinfo.authmode = wlan802_11authmodeopen; | ||
2007 | } | ||
2008 | |||
2009 | out: | ||
2010 | if (ret == 0) { | ||
2011 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
2012 | wlan_postpone_association_work(priv); | ||
2013 | } else { | ||
2014 | wlan_cancel_association_work(priv); | ||
2015 | } | ||
2016 | mutex_unlock(&adapter->lock); | ||
2017 | |||
2018 | LEAVE(); | ||
2019 | return ret; | ||
2020 | } | ||
2021 | |||
2022 | /** | ||
2023 | * @brief Get Extended Encryption key (WPA/802.1x and WEP) | ||
2024 | * | ||
2025 | * @param dev A pointer to net_device structure | ||
2026 | * @param info A pointer to iw_request_info structure | ||
2027 | * @param vwrq A pointer to iw_param structure | ||
2028 | * @param extra A pointer to extra data buf | ||
2029 | * @return 0 on success, otherwise failure | ||
2030 | */ | ||
2031 | static int wlan_get_encodeext(struct net_device *dev, | ||
2032 | struct iw_request_info *info, | ||
2033 | struct iw_point *dwrq, | ||
2034 | char *extra) | ||
2035 | { | ||
2036 | int ret = -EINVAL; | ||
2037 | wlan_private *priv = dev->priv; | ||
2038 | wlan_adapter *adapter = priv->adapter; | ||
2039 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
2040 | int index, max_key_len; | ||
2041 | |||
2042 | ENTER(); | ||
2043 | |||
2044 | max_key_len = dwrq->length - sizeof(*ext); | ||
2045 | if (max_key_len < 0) | ||
2046 | goto out; | ||
2047 | |||
2048 | index = dwrq->flags & IW_ENCODE_INDEX; | ||
2049 | if (index) { | ||
2050 | if (index < 1 || index > 4) | ||
2051 | goto out; | ||
2052 | index--; | ||
2053 | } else { | ||
2054 | index = adapter->wep_tx_keyidx; | ||
2055 | } | ||
2056 | |||
2057 | if (!ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY && | ||
2058 | ext->alg != IW_ENCODE_ALG_WEP) { | ||
2059 | if (index != 0 || adapter->inframode != wlan802_11infrastructure) | ||
2060 | goto out; | ||
2061 | } | ||
2062 | |||
2063 | dwrq->flags = index + 1; | ||
2064 | memset(ext, 0, sizeof(*ext)); | ||
2065 | |||
2066 | if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) | ||
2067 | && !adapter->secinfo.WPAenabled && !adapter->secinfo.WPA2enabled) { | ||
2068 | ext->alg = IW_ENCODE_ALG_NONE; | ||
2069 | ext->key_len = 0; | ||
2070 | dwrq->flags |= IW_ENCODE_DISABLED; | ||
2071 | } else { | ||
2072 | u8 *key = NULL; | ||
2073 | |||
2074 | if ((adapter->secinfo.WEPstatus == wlan802_11WEPenabled) | ||
2075 | && !adapter->secinfo.WPAenabled | ||
2076 | && !adapter->secinfo.WPA2enabled) { | ||
2077 | ext->alg = IW_ENCODE_ALG_WEP; | ||
2078 | ext->key_len = adapter->wep_keys[index].len; | ||
2079 | key = &adapter->wep_keys[index].key[0]; | ||
2080 | } else if ((adapter->secinfo.WEPstatus == wlan802_11WEPdisabled) && | ||
2081 | (adapter->secinfo.WPAenabled || | ||
2082 | adapter->secinfo.WPA2enabled)) { | ||
2083 | /* WPA */ | ||
2084 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
2085 | ext->key_len = 0; | ||
2086 | } else { | ||
2087 | goto out; | ||
2088 | } | ||
2089 | |||
2090 | if (ext->key_len > max_key_len) { | ||
2091 | ret = -E2BIG; | ||
2092 | goto out; | ||
2093 | } | ||
2094 | |||
2095 | if (ext->key_len) | ||
2096 | memcpy(ext->key, key, ext->key_len); | ||
2097 | else | ||
2098 | dwrq->flags |= IW_ENCODE_NOKEY; | ||
2099 | dwrq->flags |= IW_ENCODE_ENABLED; | ||
2100 | } | ||
2101 | ret = 0; | ||
2102 | |||
2103 | out: | ||
2104 | LEAVE(); | ||
2105 | return ret; | ||
2106 | } | ||
2107 | |||
2108 | /** | ||
2109 | * @brief Set Encryption key Extended (WPA/802.1x and WEP) | ||
2110 | * | ||
2111 | * @param dev A pointer to net_device structure | ||
2112 | * @param info A pointer to iw_request_info structure | ||
2113 | * @param vwrq A pointer to iw_param structure | ||
2114 | * @param extra A pointer to extra data buf | ||
2115 | * @return 0 --success, otherwise fail | ||
2116 | */ | ||
2117 | static int wlan_set_encodeext(struct net_device *dev, | ||
2118 | struct iw_request_info *info, | ||
2119 | struct iw_point *dwrq, | ||
2120 | char *extra) | ||
2121 | { | ||
2122 | int ret = 0; | ||
2123 | wlan_private *priv = dev->priv; | ||
2124 | wlan_adapter *adapter = priv->adapter; | ||
2125 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
2126 | int alg = ext->alg; | ||
2127 | struct assoc_request * assoc_req; | ||
2128 | |||
2129 | ENTER(); | ||
2130 | |||
2131 | mutex_lock(&adapter->lock); | ||
2132 | assoc_req = wlan_get_association_request(adapter); | ||
2133 | if (!assoc_req) { | ||
2134 | ret = -ENOMEM; | ||
2135 | goto out; | ||
2136 | } | ||
2137 | |||
2138 | if ((alg == IW_ENCODE_ALG_NONE) || (dwrq->flags & IW_ENCODE_DISABLED)) { | ||
2139 | disable_wep (assoc_req); | ||
2140 | } else if (alg == IW_ENCODE_ALG_WEP) { | ||
2141 | u16 is_default = 0, index, set_tx_key = 0; | ||
2142 | |||
2143 | ret = validate_key_index(assoc_req->wep_tx_keyidx, | ||
2144 | (dwrq->flags & IW_ENCODE_INDEX), | ||
2145 | &index, &is_default); | ||
2146 | if (ret) | ||
2147 | goto out; | ||
2148 | |||
2149 | /* If WEP isn't enabled, or if there is no key data but a valid | ||
2150 | * index, or if the set-TX-key flag was passed, set the TX key. | ||
2151 | */ | ||
2152 | if ((assoc_req->secinfo.WEPstatus != wlan802_11WEPenabled) | ||
2153 | || (dwrq->length == 0 && !is_default) | ||
2154 | || (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY)) | ||
2155 | set_tx_key = 1; | ||
2156 | |||
2157 | /* Copy key to driver */ | ||
2158 | ret = wlan_set_wep_key (assoc_req, ext->key, ext->key_len, index, | ||
2159 | set_tx_key); | ||
2160 | if (ret) | ||
2161 | goto out; | ||
2162 | |||
2163 | if (dwrq->flags & IW_ENCODE_RESTRICTED) { | ||
2164 | assoc_req->secinfo.authmode = | ||
2165 | wlan802_11authmodeshared; | ||
2166 | } else if (dwrq->flags & IW_ENCODE_OPEN) { | ||
2167 | assoc_req->secinfo.authmode = | ||
2168 | wlan802_11authmodeopen; | ||
2169 | } | ||
2170 | |||
2171 | /* Mark the various WEP bits as modified */ | ||
2172 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
2173 | if (dwrq->length) | ||
2174 | set_bit(ASSOC_FLAG_WEP_KEYS, &assoc_req->flags); | ||
2175 | if (set_tx_key) | ||
2176 | set_bit(ASSOC_FLAG_WEP_TX_KEYIDX, &assoc_req->flags); | ||
2177 | |||
2178 | } else if ((alg == IW_ENCODE_ALG_TKIP) || (alg == IW_ENCODE_ALG_CCMP)) { | ||
2179 | struct WLAN_802_11_KEY * pkey; | ||
2180 | |||
2181 | /* validate key length */ | ||
2182 | if (((alg == IW_ENCODE_ALG_TKIP) | ||
2183 | && (ext->key_len != KEY_LEN_WPA_TKIP)) | ||
2184 | || ((alg == IW_ENCODE_ALG_CCMP) | ||
2185 | && (ext->key_len != KEY_LEN_WPA_AES))) { | ||
2186 | lbs_pr_debug(1, "Invalid size %d for key of alg" | ||
2187 | "type %d.\n", | ||
2188 | ext->key_len, | ||
2189 | alg); | ||
2190 | ret = -EINVAL; | ||
2191 | goto out; | ||
2192 | } | ||
2193 | |||
2194 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) | ||
2195 | pkey = &assoc_req->wpa_mcast_key; | ||
2196 | else | ||
2197 | pkey = &assoc_req->wpa_unicast_key; | ||
2198 | |||
2199 | memset(pkey, 0, sizeof (struct WLAN_802_11_KEY)); | ||
2200 | memcpy(pkey->key, ext->key, ext->key_len); | ||
2201 | pkey->len = ext->key_len; | ||
2202 | pkey->flags = KEY_INFO_WPA_ENABLED; | ||
2203 | |||
2204 | if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { | ||
2205 | pkey->flags |= KEY_INFO_WPA_MCAST; | ||
2206 | set_bit(ASSOC_FLAG_WPA_MCAST_KEY, &assoc_req->flags); | ||
2207 | } else { | ||
2208 | pkey->flags |= KEY_INFO_WPA_UNICAST; | ||
2209 | set_bit(ASSOC_FLAG_WPA_UCAST_KEY, &assoc_req->flags); | ||
2210 | } | ||
2211 | |||
2212 | if (alg == IW_ENCODE_ALG_TKIP) | ||
2213 | pkey->type = KEY_TYPE_ID_TKIP; | ||
2214 | else if (alg == IW_ENCODE_ALG_CCMP) | ||
2215 | pkey->type = KEY_TYPE_ID_AES; | ||
2216 | |||
2217 | /* If WPA isn't enabled yet, do that now */ | ||
2218 | if ( assoc_req->secinfo.WPAenabled == 0 | ||
2219 | && assoc_req->secinfo.WPA2enabled == 0) { | ||
2220 | assoc_req->secinfo.WPAenabled = 1; | ||
2221 | assoc_req->secinfo.WPA2enabled = 1; | ||
2222 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
2223 | } | ||
2224 | |||
2225 | disable_wep (assoc_req); | ||
2226 | } | ||
2227 | |||
2228 | out: | ||
2229 | if (ret == 0) { | ||
2230 | wlan_postpone_association_work(priv); | ||
2231 | } else { | ||
2232 | wlan_cancel_association_work(priv); | ||
2233 | } | ||
2234 | mutex_unlock(&adapter->lock); | ||
2235 | |||
2236 | LEAVE(); | ||
2237 | return ret; | ||
2238 | } | ||
2239 | |||
2240 | |||
2241 | static int wlan_set_genie(struct net_device *dev, | ||
2242 | struct iw_request_info *info, | ||
2243 | struct iw_point *dwrq, | ||
2244 | char *extra) | ||
2245 | { | ||
2246 | wlan_private *priv = dev->priv; | ||
2247 | wlan_adapter *adapter = priv->adapter; | ||
2248 | int ret = 0; | ||
2249 | struct assoc_request * assoc_req; | ||
2250 | |||
2251 | ENTER(); | ||
2252 | |||
2253 | mutex_lock(&adapter->lock); | ||
2254 | assoc_req = wlan_get_association_request(adapter); | ||
2255 | if (!assoc_req) { | ||
2256 | ret = -ENOMEM; | ||
2257 | goto out; | ||
2258 | } | ||
2259 | |||
2260 | if (dwrq->length > MAX_WPA_IE_LEN || | ||
2261 | (dwrq->length && extra == NULL)) { | ||
2262 | ret = -EINVAL; | ||
2263 | goto out; | ||
2264 | } | ||
2265 | |||
2266 | if (dwrq->length) { | ||
2267 | memcpy(&assoc_req->wpa_ie[0], extra, dwrq->length); | ||
2268 | assoc_req->wpa_ie_len = dwrq->length; | ||
2269 | } else { | ||
2270 | memset(&assoc_req->wpa_ie[0], 0, sizeof(adapter->wpa_ie)); | ||
2271 | assoc_req->wpa_ie_len = 0; | ||
2272 | } | ||
2273 | |||
2274 | out: | ||
2275 | if (ret == 0) { | ||
2276 | set_bit(ASSOC_FLAG_WPA_IE, &assoc_req->flags); | ||
2277 | wlan_postpone_association_work(priv); | ||
2278 | } else { | ||
2279 | wlan_cancel_association_work(priv); | ||
2280 | } | ||
2281 | mutex_unlock(&adapter->lock); | ||
2282 | |||
2283 | LEAVE(); | ||
2284 | return ret; | ||
2285 | } | ||
2286 | |||
2287 | static int wlan_get_genie(struct net_device *dev, | ||
2288 | struct iw_request_info *info, | ||
2289 | struct iw_point *dwrq, | ||
2290 | char *extra) | ||
2291 | { | ||
2292 | wlan_private *priv = dev->priv; | ||
2293 | wlan_adapter *adapter = priv->adapter; | ||
2294 | |||
2295 | ENTER(); | ||
2296 | |||
2297 | if (adapter->wpa_ie_len == 0) { | ||
2298 | dwrq->length = 0; | ||
2299 | LEAVE(); | ||
2300 | return 0; | ||
2301 | } | ||
2302 | |||
2303 | if (dwrq->length < adapter->wpa_ie_len) { | ||
2304 | LEAVE(); | ||
2305 | return -E2BIG; | ||
2306 | } | ||
2307 | |||
2308 | dwrq->length = adapter->wpa_ie_len; | ||
2309 | memcpy(extra, &adapter->wpa_ie[0], adapter->wpa_ie_len); | ||
2310 | |||
2311 | LEAVE(); | ||
2312 | return 0; | ||
2313 | } | ||
2314 | |||
2315 | |||
2316 | static int wlan_set_auth(struct net_device *dev, | ||
2317 | struct iw_request_info *info, | ||
2318 | struct iw_param *dwrq, | ||
2319 | char *extra) | ||
2320 | { | ||
2321 | wlan_private *priv = dev->priv; | ||
2322 | wlan_adapter *adapter = priv->adapter; | ||
2323 | struct assoc_request * assoc_req; | ||
2324 | int ret = 0; | ||
2325 | int updated = 0; | ||
2326 | |||
2327 | ENTER(); | ||
2328 | |||
2329 | mutex_lock(&adapter->lock); | ||
2330 | assoc_req = wlan_get_association_request(adapter); | ||
2331 | if (!assoc_req) { | ||
2332 | ret = -ENOMEM; | ||
2333 | goto out; | ||
2334 | } | ||
2335 | |||
2336 | switch (dwrq->flags & IW_AUTH_INDEX) { | ||
2337 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
2338 | case IW_AUTH_CIPHER_PAIRWISE: | ||
2339 | case IW_AUTH_CIPHER_GROUP: | ||
2340 | case IW_AUTH_KEY_MGMT: | ||
2341 | /* | ||
2342 | * libertas does not use these parameters | ||
2343 | */ | ||
2344 | break; | ||
2345 | |||
2346 | case IW_AUTH_WPA_VERSION: | ||
2347 | if (dwrq->value & IW_AUTH_WPA_VERSION_DISABLED) { | ||
2348 | assoc_req->secinfo.WPAenabled = 0; | ||
2349 | assoc_req->secinfo.WPA2enabled = 0; | ||
2350 | } | ||
2351 | if (dwrq->value & IW_AUTH_WPA_VERSION_WPA) { | ||
2352 | assoc_req->secinfo.WPAenabled = 1; | ||
2353 | assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; | ||
2354 | assoc_req->secinfo.authmode = | ||
2355 | wlan802_11authmodeopen; | ||
2356 | } | ||
2357 | if (dwrq->value & IW_AUTH_WPA_VERSION_WPA2) { | ||
2358 | assoc_req->secinfo.WPA2enabled = 1; | ||
2359 | assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; | ||
2360 | assoc_req->secinfo.authmode = | ||
2361 | wlan802_11authmodeopen; | ||
2362 | } | ||
2363 | updated = 1; | ||
2364 | break; | ||
2365 | |||
2366 | case IW_AUTH_DROP_UNENCRYPTED: | ||
2367 | if (dwrq->value) { | ||
2368 | adapter->currentpacketfilter |= | ||
2369 | cmd_act_mac_strict_protection_enable; | ||
2370 | } else { | ||
2371 | adapter->currentpacketfilter &= | ||
2372 | ~cmd_act_mac_strict_protection_enable; | ||
2373 | } | ||
2374 | updated = 1; | ||
2375 | break; | ||
2376 | |||
2377 | case IW_AUTH_80211_AUTH_ALG: | ||
2378 | if (dwrq->value & IW_AUTH_ALG_SHARED_KEY) { | ||
2379 | assoc_req->secinfo.authmode = | ||
2380 | wlan802_11authmodeshared; | ||
2381 | } else if (dwrq->value & IW_AUTH_ALG_OPEN_SYSTEM) { | ||
2382 | assoc_req->secinfo.authmode = | ||
2383 | wlan802_11authmodeopen; | ||
2384 | } else if (dwrq->value & IW_AUTH_ALG_LEAP) { | ||
2385 | assoc_req->secinfo.authmode = | ||
2386 | wlan802_11authmodenetworkEAP; | ||
2387 | } else { | ||
2388 | ret = -EINVAL; | ||
2389 | } | ||
2390 | updated = 1; | ||
2391 | break; | ||
2392 | |||
2393 | case IW_AUTH_WPA_ENABLED: | ||
2394 | if (dwrq->value) { | ||
2395 | if (!assoc_req->secinfo.WPAenabled && | ||
2396 | !assoc_req->secinfo.WPA2enabled) { | ||
2397 | assoc_req->secinfo.WPAenabled = 1; | ||
2398 | assoc_req->secinfo.WPA2enabled = 1; | ||
2399 | assoc_req->secinfo.WEPstatus = wlan802_11WEPdisabled; | ||
2400 | assoc_req->secinfo.authmode = | ||
2401 | wlan802_11authmodeopen; | ||
2402 | } | ||
2403 | } else { | ||
2404 | assoc_req->secinfo.WPAenabled = 0; | ||
2405 | assoc_req->secinfo.WPA2enabled = 0; | ||
2406 | } | ||
2407 | updated = 1; | ||
2408 | break; | ||
2409 | |||
2410 | default: | ||
2411 | ret = -EOPNOTSUPP; | ||
2412 | break; | ||
2413 | } | ||
2414 | |||
2415 | out: | ||
2416 | if (ret == 0) { | ||
2417 | if (updated) | ||
2418 | set_bit(ASSOC_FLAG_SECINFO, &assoc_req->flags); | ||
2419 | wlan_postpone_association_work(priv); | ||
2420 | } else if (ret != -EOPNOTSUPP) { | ||
2421 | wlan_cancel_association_work(priv); | ||
2422 | } | ||
2423 | mutex_unlock(&adapter->lock); | ||
2424 | |||
2425 | LEAVE(); | ||
2426 | return ret; | ||
2427 | } | ||
2428 | |||
2429 | static int wlan_get_auth(struct net_device *dev, | ||
2430 | struct iw_request_info *info, | ||
2431 | struct iw_param *dwrq, | ||
2432 | char *extra) | ||
2433 | { | ||
2434 | wlan_private *priv = dev->priv; | ||
2435 | wlan_adapter *adapter = priv->adapter; | ||
2436 | |||
2437 | ENTER(); | ||
2438 | |||
2439 | switch (dwrq->flags & IW_AUTH_INDEX) { | ||
2440 | case IW_AUTH_WPA_VERSION: | ||
2441 | dwrq->value = 0; | ||
2442 | if (adapter->secinfo.WPAenabled) | ||
2443 | dwrq->value |= IW_AUTH_WPA_VERSION_WPA; | ||
2444 | if (adapter->secinfo.WPA2enabled) | ||
2445 | dwrq->value |= IW_AUTH_WPA_VERSION_WPA2; | ||
2446 | if (!dwrq->value) | ||
2447 | dwrq->value |= IW_AUTH_WPA_VERSION_DISABLED; | ||
2448 | break; | ||
2449 | |||
2450 | case IW_AUTH_DROP_UNENCRYPTED: | ||
2451 | dwrq->value = 0; | ||
2452 | if (adapter->currentpacketfilter & | ||
2453 | cmd_act_mac_strict_protection_enable) | ||
2454 | dwrq->value = 1; | ||
2455 | break; | ||
2456 | |||
2457 | case IW_AUTH_80211_AUTH_ALG: | ||
2458 | switch (adapter->secinfo.authmode) { | ||
2459 | case wlan802_11authmodeshared: | ||
2460 | dwrq->value = IW_AUTH_ALG_SHARED_KEY; | ||
2461 | break; | ||
2462 | case wlan802_11authmodeopen: | ||
2463 | dwrq->value = IW_AUTH_ALG_OPEN_SYSTEM; | ||
2464 | break; | ||
2465 | case wlan802_11authmodenetworkEAP: | ||
2466 | dwrq->value = IW_AUTH_ALG_LEAP; | ||
2467 | break; | ||
2468 | default: | ||
2469 | break; | ||
2470 | } | ||
2471 | break; | ||
2472 | |||
2473 | case IW_AUTH_WPA_ENABLED: | ||
2474 | if (adapter->secinfo.WPAenabled && adapter->secinfo.WPA2enabled) | ||
2475 | dwrq->value = 1; | ||
2476 | break; | ||
2477 | |||
2478 | default: | ||
2479 | LEAVE(); | ||
2480 | return -EOPNOTSUPP; | ||
2481 | } | ||
2482 | |||
2483 | LEAVE(); | ||
2484 | return 0; | ||
2485 | } | ||
2486 | |||
2487 | |||
2488 | static int wlan_set_txpow(struct net_device *dev, struct iw_request_info *info, | ||
2489 | struct iw_param *vwrq, char *extra) | ||
2490 | { | ||
2491 | int ret = 0; | ||
2492 | wlan_private *priv = dev->priv; | ||
2493 | wlan_adapter *adapter = priv->adapter; | ||
2494 | |||
2495 | u16 dbm; | ||
2496 | |||
2497 | ENTER(); | ||
2498 | |||
2499 | if (vwrq->disabled) { | ||
2500 | wlan_radio_ioctl(priv, RADIO_OFF); | ||
2501 | return 0; | ||
2502 | } | ||
2503 | |||
2504 | adapter->preamble = cmd_type_auto_preamble; | ||
2505 | |||
2506 | wlan_radio_ioctl(priv, RADIO_ON); | ||
2507 | |||
2508 | if ((vwrq->flags & IW_TXPOW_TYPE) == IW_TXPOW_MWATT) { | ||
2509 | dbm = (u16) mw_to_dbm(vwrq->value); | ||
2510 | } else | ||
2511 | dbm = (u16) vwrq->value; | ||
2512 | |||
2513 | /* auto tx power control */ | ||
2514 | |||
2515 | if (vwrq->fixed == 0) | ||
2516 | dbm = 0xffff; | ||
2517 | |||
2518 | lbs_pr_debug(1, "<1>TXPOWER SET %d dbm.\n", dbm); | ||
2519 | |||
2520 | ret = libertas_prepare_and_send_command(priv, | ||
2521 | cmd_802_11_rf_tx_power, | ||
2522 | cmd_act_tx_power_opt_set_low, | ||
2523 | cmd_option_waitforrsp, 0, (void *)&dbm); | ||
2524 | |||
2525 | LEAVE(); | ||
2526 | return ret; | ||
2527 | } | ||
2528 | |||
2529 | static int wlan_get_essid(struct net_device *dev, struct iw_request_info *info, | ||
2530 | struct iw_point *dwrq, char *extra) | ||
2531 | { | ||
2532 | wlan_private *priv = dev->priv; | ||
2533 | wlan_adapter *adapter = priv->adapter; | ||
2534 | |||
2535 | ENTER(); | ||
2536 | /* | ||
2537 | * Note : if dwrq->flags != 0, we should get the relevant SSID from | ||
2538 | * the SSID list... | ||
2539 | */ | ||
2540 | |||
2541 | /* | ||
2542 | * Get the current SSID | ||
2543 | */ | ||
2544 | if (adapter->connect_status == libertas_connected) { | ||
2545 | memcpy(extra, adapter->curbssparams.ssid.ssid, | ||
2546 | adapter->curbssparams.ssid.ssidlength); | ||
2547 | extra[adapter->curbssparams.ssid.ssidlength] = '\0'; | ||
2548 | } else { | ||
2549 | memset(extra, 0, 32); | ||
2550 | extra[adapter->curbssparams.ssid.ssidlength] = '\0'; | ||
2551 | } | ||
2552 | /* | ||
2553 | * If none, we may want to get the one that was set | ||
2554 | */ | ||
2555 | |||
2556 | /* To make the driver backward compatible with WPA supplicant v0.2.4 */ | ||
2557 | if (dwrq->length == 32) /* check with WPA supplicant buffer size */ | ||
2558 | dwrq->length = min_t(size_t, adapter->curbssparams.ssid.ssidlength, | ||
2559 | IW_ESSID_MAX_SIZE); | ||
2560 | else | ||
2561 | dwrq->length = adapter->curbssparams.ssid.ssidlength + 1; | ||
2562 | |||
2563 | dwrq->flags = 1; /* active */ | ||
2564 | |||
2565 | LEAVE(); | ||
2566 | return 0; | ||
2567 | } | ||
2568 | |||
2569 | static int wlan_set_essid(struct net_device *dev, struct iw_request_info *info, | ||
2570 | struct iw_point *dwrq, char *extra) | ||
2571 | { | ||
2572 | wlan_private *priv = dev->priv; | ||
2573 | wlan_adapter *adapter = priv->adapter; | ||
2574 | int ret = 0; | ||
2575 | struct WLAN_802_11_SSID ssid; | ||
2576 | struct assoc_request * assoc_req; | ||
2577 | int ssid_len = dwrq->length; | ||
2578 | |||
2579 | ENTER(); | ||
2580 | |||
2581 | /* | ||
2582 | * WE-20 and earlier NULL pad the end of the SSID and increment | ||
2583 | * SSID length so it can be used like a string. WE-21 and later don't, | ||
2584 | * but some userspace tools aren't able to cope with the change. | ||
2585 | */ | ||
2586 | if ((ssid_len > 0) && (extra[ssid_len - 1] == '\0')) | ||
2587 | ssid_len--; | ||
2588 | |||
2589 | /* Check the size of the string */ | ||
2590 | if (ssid_len > IW_ESSID_MAX_SIZE) { | ||
2591 | ret = -E2BIG; | ||
2592 | goto out; | ||
2593 | } | ||
2594 | |||
2595 | memset(&ssid, 0, sizeof(struct WLAN_802_11_SSID)); | ||
2596 | |||
2597 | if (!dwrq->flags || !ssid_len) { | ||
2598 | /* "any" SSID requested; leave SSID blank */ | ||
2599 | } else { | ||
2600 | /* Specific SSID requested */ | ||
2601 | memcpy(&ssid.ssid, extra, ssid_len); | ||
2602 | ssid.ssidlength = ssid_len; | ||
2603 | } | ||
2604 | |||
2605 | lbs_pr_debug(1, "Requested new SSID = %s\n", | ||
2606 | (ssid.ssidlength > 0) ? (char *)ssid.ssid : "any"); | ||
2607 | |||
2608 | out: | ||
2609 | mutex_lock(&adapter->lock); | ||
2610 | if (ret == 0) { | ||
2611 | /* Get or create the current association request */ | ||
2612 | assoc_req = wlan_get_association_request(adapter); | ||
2613 | if (!assoc_req) { | ||
2614 | ret = -ENOMEM; | ||
2615 | } else { | ||
2616 | /* Copy the SSID to the association request */ | ||
2617 | memcpy(&assoc_req->ssid, &ssid, sizeof(struct WLAN_802_11_SSID)); | ||
2618 | set_bit(ASSOC_FLAG_SSID, &assoc_req->flags); | ||
2619 | wlan_postpone_association_work(priv); | ||
2620 | } | ||
2621 | } | ||
2622 | |||
2623 | /* Cancel the association request if there was an error */ | ||
2624 | if (ret != 0) { | ||
2625 | wlan_cancel_association_work(priv); | ||
2626 | } | ||
2627 | |||
2628 | mutex_unlock(&adapter->lock); | ||
2629 | |||
2630 | LEAVE(); | ||
2631 | return ret; | ||
2632 | } | ||
2633 | |||
2634 | /** | ||
2635 | * @brief Connect to the AP or Ad-hoc Network with specific bssid | ||
2636 | * | ||
2637 | * @param dev A pointer to net_device structure | ||
2638 | * @param info A pointer to iw_request_info structure | ||
2639 | * @param awrq A pointer to iw_param structure | ||
2640 | * @param extra A pointer to extra data buf | ||
2641 | * @return 0 --success, otherwise fail | ||
2642 | */ | ||
2643 | static int wlan_set_wap(struct net_device *dev, struct iw_request_info *info, | ||
2644 | struct sockaddr *awrq, char *extra) | ||
2645 | { | ||
2646 | wlan_private *priv = dev->priv; | ||
2647 | wlan_adapter *adapter = priv->adapter; | ||
2648 | struct assoc_request * assoc_req; | ||
2649 | int ret = 0; | ||
2650 | |||
2651 | ENTER(); | ||
2652 | |||
2653 | if (awrq->sa_family != ARPHRD_ETHER) | ||
2654 | return -EINVAL; | ||
2655 | |||
2656 | lbs_pr_debug(1, "ASSOC: WAP: sa_data: " MAC_FMT "\n", MAC_ARG(awrq->sa_data)); | ||
2657 | |||
2658 | mutex_lock(&adapter->lock); | ||
2659 | |||
2660 | /* Get or create the current association request */ | ||
2661 | assoc_req = wlan_get_association_request(adapter); | ||
2662 | if (!assoc_req) { | ||
2663 | wlan_cancel_association_work(priv); | ||
2664 | ret = -ENOMEM; | ||
2665 | } else { | ||
2666 | /* Copy the BSSID to the association request */ | ||
2667 | memcpy(&assoc_req->bssid, awrq->sa_data, ETH_ALEN); | ||
2668 | set_bit(ASSOC_FLAG_BSSID, &assoc_req->flags); | ||
2669 | wlan_postpone_association_work(priv); | ||
2670 | } | ||
2671 | |||
2672 | mutex_unlock(&adapter->lock); | ||
2673 | |||
2674 | return ret; | ||
2675 | } | ||
2676 | |||
2677 | void libertas_get_fwversion(wlan_adapter * adapter, char *fwversion, int maxlen) | ||
2678 | { | ||
2679 | union { | ||
2680 | u32 l; | ||
2681 | u8 c[4]; | ||
2682 | } ver; | ||
2683 | char fwver[32]; | ||
2684 | |||
2685 | mutex_lock(&adapter->lock); | ||
2686 | ver.l = adapter->fwreleasenumber; | ||
2687 | mutex_unlock(&adapter->lock); | ||
2688 | |||
2689 | if (ver.c[3] == 0) | ||
2690 | sprintf(fwver, "%u.%u.%u", ver.c[2], ver.c[1], ver.c[0]); | ||
2691 | else | ||
2692 | sprintf(fwver, "%u.%u.%u.p%u", | ||
2693 | ver.c[2], ver.c[1], ver.c[0], ver.c[3]); | ||
2694 | |||
2695 | snprintf(fwversion, maxlen, fwver); | ||
2696 | } | ||
2697 | |||
2698 | |||
2699 | /* | ||
2700 | * iwconfig settable callbacks | ||
2701 | */ | ||
2702 | static const iw_handler wlan_handler[] = { | ||
2703 | (iw_handler) NULL, /* SIOCSIWCOMMIT */ | ||
2704 | (iw_handler) wlan_get_name, /* SIOCGIWNAME */ | ||
2705 | (iw_handler) NULL, /* SIOCSIWNWID */ | ||
2706 | (iw_handler) NULL, /* SIOCGIWNWID */ | ||
2707 | (iw_handler) wlan_set_freq, /* SIOCSIWFREQ */ | ||
2708 | (iw_handler) wlan_get_freq, /* SIOCGIWFREQ */ | ||
2709 | (iw_handler) wlan_set_mode, /* SIOCSIWMODE */ | ||
2710 | (iw_handler) wlan_get_mode, /* SIOCGIWMODE */ | ||
2711 | (iw_handler) NULL, /* SIOCSIWSENS */ | ||
2712 | (iw_handler) NULL, /* SIOCGIWSENS */ | ||
2713 | (iw_handler) NULL, /* SIOCSIWRANGE */ | ||
2714 | (iw_handler) wlan_get_range, /* SIOCGIWRANGE */ | ||
2715 | (iw_handler) NULL, /* SIOCSIWPRIV */ | ||
2716 | (iw_handler) NULL, /* SIOCGIWPRIV */ | ||
2717 | (iw_handler) NULL, /* SIOCSIWSTATS */ | ||
2718 | (iw_handler) NULL, /* SIOCGIWSTATS */ | ||
2719 | iw_handler_set_spy, /* SIOCSIWSPY */ | ||
2720 | iw_handler_get_spy, /* SIOCGIWSPY */ | ||
2721 | iw_handler_set_thrspy, /* SIOCSIWTHRSPY */ | ||
2722 | iw_handler_get_thrspy, /* SIOCGIWTHRSPY */ | ||
2723 | (iw_handler) wlan_set_wap, /* SIOCSIWAP */ | ||
2724 | (iw_handler) wlan_get_wap, /* SIOCGIWAP */ | ||
2725 | (iw_handler) NULL, /* SIOCSIWMLME */ | ||
2726 | (iw_handler) NULL, /* SIOCGIWAPLIST - deprecated */ | ||
2727 | (iw_handler) libertas_set_scan, /* SIOCSIWSCAN */ | ||
2728 | (iw_handler) libertas_get_scan, /* SIOCGIWSCAN */ | ||
2729 | (iw_handler) wlan_set_essid, /* SIOCSIWESSID */ | ||
2730 | (iw_handler) wlan_get_essid, /* SIOCGIWESSID */ | ||
2731 | (iw_handler) wlan_set_nick, /* SIOCSIWNICKN */ | ||
2732 | (iw_handler) wlan_get_nick, /* SIOCGIWNICKN */ | ||
2733 | (iw_handler) NULL, /* -- hole -- */ | ||
2734 | (iw_handler) NULL, /* -- hole -- */ | ||
2735 | (iw_handler) wlan_set_rate, /* SIOCSIWRATE */ | ||
2736 | (iw_handler) wlan_get_rate, /* SIOCGIWRATE */ | ||
2737 | (iw_handler) wlan_set_rts, /* SIOCSIWRTS */ | ||
2738 | (iw_handler) wlan_get_rts, /* SIOCGIWRTS */ | ||
2739 | (iw_handler) wlan_set_frag, /* SIOCSIWFRAG */ | ||
2740 | (iw_handler) wlan_get_frag, /* SIOCGIWFRAG */ | ||
2741 | (iw_handler) wlan_set_txpow, /* SIOCSIWTXPOW */ | ||
2742 | (iw_handler) wlan_get_txpow, /* SIOCGIWTXPOW */ | ||
2743 | (iw_handler) wlan_set_retry, /* SIOCSIWRETRY */ | ||
2744 | (iw_handler) wlan_get_retry, /* SIOCGIWRETRY */ | ||
2745 | (iw_handler) wlan_set_encode, /* SIOCSIWENCODE */ | ||
2746 | (iw_handler) wlan_get_encode, /* SIOCGIWENCODE */ | ||
2747 | (iw_handler) wlan_set_power, /* SIOCSIWPOWER */ | ||
2748 | (iw_handler) wlan_get_power, /* SIOCGIWPOWER */ | ||
2749 | (iw_handler) NULL, /* -- hole -- */ | ||
2750 | (iw_handler) NULL, /* -- hole -- */ | ||
2751 | (iw_handler) wlan_set_genie, /* SIOCSIWGENIE */ | ||
2752 | (iw_handler) wlan_get_genie, /* SIOCGIWGENIE */ | ||
2753 | (iw_handler) wlan_set_auth, /* SIOCSIWAUTH */ | ||
2754 | (iw_handler) wlan_get_auth, /* SIOCGIWAUTH */ | ||
2755 | (iw_handler) wlan_set_encodeext,/* SIOCSIWENCODEEXT */ | ||
2756 | (iw_handler) wlan_get_encodeext,/* SIOCGIWENCODEEXT */ | ||
2757 | (iw_handler) NULL, /* SIOCSIWPMKSA */ | ||
2758 | }; | ||
2759 | |||
2760 | struct iw_handler_def libertas_handler_def = { | ||
2761 | .num_standard = sizeof(wlan_handler) / sizeof(iw_handler), | ||
2762 | .num_private = sizeof(wlan_private_handler) / sizeof(iw_handler), | ||
2763 | .num_private_args = sizeof(wlan_private_args) / | ||
2764 | sizeof(struct iw_priv_args), | ||
2765 | .standard = (iw_handler *) wlan_handler, | ||
2766 | .private = (iw_handler *) wlan_private_handler, | ||
2767 | .private_args = (struct iw_priv_args *)wlan_private_args, | ||
2768 | .get_wireless_stats = wlan_get_wireless_stats, | ||
2769 | }; | ||
diff --git a/drivers/net/wireless/libertas/wext.h b/drivers/net/wireless/libertas/wext.h new file mode 100644 index 000000000000..39f367c38d90 --- /dev/null +++ b/drivers/net/wireless/libertas/wext.h | |||
@@ -0,0 +1,147 @@ | |||
1 | /** | ||
2 | * This file contains definition for IOCTL call. | ||
3 | */ | ||
4 | #ifndef _WLAN_WEXT_H_ | ||
5 | #define _WLAN_WEXT_H_ | ||
6 | |||
7 | #define SUBCMD_OFFSET 4 | ||
8 | #define SUBCMD_DATA(x) *((int *)(x->u.name + SUBCMD_OFFSET)) | ||
9 | |||
10 | /** PRIVATE CMD ID */ | ||
11 | #define WLANIOCTL SIOCIWFIRSTPRIV | ||
12 | |||
13 | #define WLANSETWPAIE (WLANIOCTL + 0) | ||
14 | |||
15 | #define WLAN_SETINT_GETINT (WLANIOCTL + 7) | ||
16 | #define WLANNF 1 | ||
17 | #define WLANRSSI 2 | ||
18 | #define WLANENABLE11D 5 | ||
19 | #define WLANADHOCGRATE 6 | ||
20 | #define WLAN_SUBCMD_SET_PRESCAN 11 | ||
21 | |||
22 | #define WLAN_SETNONE_GETNONE (WLANIOCTL + 8) | ||
23 | #define WLANDEAUTH 1 | ||
24 | #define WLANRADIOON 2 | ||
25 | #define WLANRADIOOFF 3 | ||
26 | #define WLANREMOVEADHOCAES 4 | ||
27 | #define WLANADHOCSTOP 5 | ||
28 | #define WLANCIPHERTEST 6 | ||
29 | #define WLANCRYPTOTEST 7 | ||
30 | |||
31 | #define WLANWLANIDLEON 10 | ||
32 | #define WLANWLANIDLEOFF 11 | ||
33 | #define WLAN_SUBCMD_BT_RESET 13 | ||
34 | #define WLAN_SUBCMD_FWT_RESET 14 | ||
35 | |||
36 | #define WLANGETLOG (WLANIOCTL + 9) | ||
37 | #define GETLOG_BUFSIZE 300 | ||
38 | |||
39 | #define WLANSCAN_TYPE (WLANIOCTL + 11) | ||
40 | |||
41 | #define WLAN_SETNONE_GETONEINT (WLANIOCTL + 15) | ||
42 | #define WLANGETREGION 1 | ||
43 | #define WLAN_GET_LISTEN_INTERVAL 2 | ||
44 | #define WLAN_GET_MULTIPLE_DTIM 3 | ||
45 | #define WLAN_GET_TX_RATE 4 | ||
46 | #define WLANGETBCNAVG 5 | ||
47 | |||
48 | #define WLAN_GET_LINKMODE 6 | ||
49 | #define WLAN_GET_RADIOMODE 7 | ||
50 | #define WLAN_GET_DEBUGMODE 8 | ||
51 | #define WLAN_SUBCMD_FWT_CLEANUP 15 | ||
52 | #define WLAN_SUBCMD_FWT_TIME 16 | ||
53 | #define WLAN_SUBCMD_MESH_GET_TTL 17 | ||
54 | |||
55 | #define WLANREGCFRDWR (WLANIOCTL + 18) | ||
56 | |||
57 | #define WLAN_SETNONE_GETTWELVE_CHAR (WLANIOCTL + 19) | ||
58 | #define WLAN_SUBCMD_GETRXANTENNA 1 | ||
59 | #define WLAN_SUBCMD_GETTXANTENNA 2 | ||
60 | #define WLAN_GET_TSF 3 | ||
61 | |||
62 | #define WLAN_SETNONE_GETWORDCHAR (WLANIOCTL + 21) | ||
63 | #define WLANGETADHOCAES 1 | ||
64 | |||
65 | #define WLAN_SETONEINT_GETONEINT (WLANIOCTL + 23) | ||
66 | #define WLAN_BEACON_INTERVAL 1 | ||
67 | #define WLAN_LISTENINTRVL 4 | ||
68 | |||
69 | #define WLAN_TXCONTROL 6 | ||
70 | #define WLAN_NULLPKTINTERVAL 7 | ||
71 | |||
72 | #define WLAN_SETONEINT_GETNONE (WLANIOCTL + 24) | ||
73 | #define WLAN_SUBCMD_SETRXANTENNA 1 | ||
74 | #define WLAN_SUBCMD_SETTXANTENNA 2 | ||
75 | #define WLANSETAUTHALG 5 | ||
76 | #define WLANSET8021XAUTHALG 6 | ||
77 | #define WLANSETENCRYPTIONMODE 7 | ||
78 | #define WLANSETREGION 8 | ||
79 | #define WLAN_SET_LISTEN_INTERVAL 9 | ||
80 | |||
81 | #define WLAN_SET_MULTIPLE_DTIM 10 | ||
82 | #define WLAN_SET_ATIM_WINDOW 11 | ||
83 | #define WLANSETBCNAVG 13 | ||
84 | #define WLANSETDATAAVG 14 | ||
85 | #define WLAN_SET_LINKMODE 15 | ||
86 | #define WLAN_SET_RADIOMODE 16 | ||
87 | #define WLAN_SET_DEBUGMODE 17 | ||
88 | #define WLAN_SUBCMD_MESH_SET_TTL 18 | ||
89 | |||
90 | #define WLAN_SET128CHAR_GET128CHAR (WLANIOCTL + 25) | ||
91 | #define WLANSCAN_MODE 6 | ||
92 | |||
93 | #define WLAN_GET_ADHOC_STATUS 9 | ||
94 | |||
95 | #define WLAN_SUBCMD_BT_ADD 18 | ||
96 | #define WLAN_SUBCMD_BT_DEL 19 | ||
97 | #define WLAN_SUBCMD_BT_LIST 20 | ||
98 | #define WLAN_SUBCMD_FWT_ADD 21 | ||
99 | #define WLAN_SUBCMD_FWT_DEL 22 | ||
100 | #define WLAN_SUBCMD_FWT_LOOKUP 23 | ||
101 | #define WLAN_SUBCMD_FWT_LIST_NEIGHBOR 24 | ||
102 | #define WLAN_SUBCMD_FWT_LIST 25 | ||
103 | #define WLAN_SUBCMD_FWT_LIST_ROUTE 26 | ||
104 | |||
105 | #define WLAN_SET_GET_SIXTEEN_INT (WLANIOCTL + 29) | ||
106 | #define WLAN_TPCCFG 1 | ||
107 | #define WLAN_POWERCFG 2 | ||
108 | |||
109 | #define WLAN_AUTO_FREQ_SET 3 | ||
110 | #define WLAN_AUTO_FREQ_GET 4 | ||
111 | #define WLAN_LED_GPIO_CTRL 5 | ||
112 | #define WLAN_SCANPROBES 6 | ||
113 | #define WLAN_ADAPT_RATESET 8 | ||
114 | #define WLAN_INACTIVITY_TIMEOUT 9 | ||
115 | #define WLANSNR 10 | ||
116 | #define WLAN_GET_RATE 11 | ||
117 | #define WLAN_GET_RXINFO 12 | ||
118 | |||
119 | #define WLANCMD52RDWR (WLANIOCTL + 30) | ||
120 | #define WLANCMD53RDWR (WLANIOCTL + 31) | ||
121 | #define CMD53BUFLEN 32 | ||
122 | |||
123 | #define REG_MAC 0x19 | ||
124 | #define REG_BBP 0x1a | ||
125 | #define REG_RF 0x1b | ||
126 | #define REG_EEPROM 0x59 | ||
127 | #define WLAN_LINKMODE_802_3 0 | ||
128 | #define WLAN_LINKMODE_802_11 2 | ||
129 | #define WLAN_RADIOMODE_NONE 0 | ||
130 | #define WLAN_RADIOMODE_RADIOTAP 2 | ||
131 | |||
132 | /** wlan_ioctl_regrdwr */ | ||
133 | struct wlan_ioctl_regrdwr { | ||
134 | /** Which register to access */ | ||
135 | u16 whichreg; | ||
136 | /** Read or Write */ | ||
137 | u16 action; | ||
138 | u32 offset; | ||
139 | u16 NOB; | ||
140 | u32 value; | ||
141 | }; | ||
142 | |||
143 | extern struct iw_handler_def libertas_handler_def; | ||
144 | int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int i); | ||
145 | int wlan_radio_ioctl(wlan_private * priv, u8 option); | ||
146 | |||
147 | #endif /* _WLAN_WEXT_H_ */ | ||
diff --git a/drivers/net/wireless/todo.txt b/drivers/net/wireless/todo.txt deleted file mode 100644 index 32234018de72..000000000000 --- a/drivers/net/wireless/todo.txt +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | Wireless Todo | ||
2 | ------------- | ||
3 | |||
4 | 1) Bring other kernel Wireless LAN drivers here | ||
5 | Completed | ||
6 | |||
7 | 2) Bring new Wireless LAN driver not yet in the kernel there | ||
8 | See my web page for details | ||
9 | In particular : HostAP | ||
10 | |||
11 | 3) Misc | ||
12 | o Mark wavelan, wavelan_cs, netwave_cs drivers as obsolete | ||
13 | o Maybe arlan.c, ray_cs.c and strip.c also deserve to be obsolete | ||
14 | |||
15 | Jean II | ||
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index 87ee3ee020fe..95b4a2a26707 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c | |||
@@ -67,11 +67,12 @@ static int scnprint_id(struct zd_chip *chip, char *buffer, size_t size) | |||
67 | i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i); | 67 | i += scnprint_mac_oui(chip->e2p_mac, buffer+i, size-i); |
68 | i += scnprintf(buffer+i, size-i, " "); | 68 | i += scnprintf(buffer+i, size-i, " "); |
69 | i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i); | 69 | i += zd_rf_scnprint_id(&chip->rf, buffer+i, size-i); |
70 | i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c", chip->pa_type, | 70 | i += scnprintf(buffer+i, size-i, " pa%1x %c%c%c%c%c", chip->pa_type, |
71 | chip->patch_cck_gain ? 'g' : '-', | 71 | chip->patch_cck_gain ? 'g' : '-', |
72 | chip->patch_cr157 ? '7' : '-', | 72 | chip->patch_cr157 ? '7' : '-', |
73 | chip->patch_6m_band_edge ? '6' : '-', | 73 | chip->patch_6m_band_edge ? '6' : '-', |
74 | chip->new_phy_layout ? 'N' : '-'); | 74 | chip->new_phy_layout ? 'N' : '-', |
75 | chip->al2230s_bit ? 'S' : '-'); | ||
75 | return i; | 76 | return i; |
76 | } | 77 | } |
77 | 78 | ||
@@ -114,7 +115,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr | |||
114 | /* Allocate a single memory block for values and addresses. */ | 115 | /* Allocate a single memory block for values and addresses. */ |
115 | count16 = 2*count; | 116 | count16 = 2*count; |
116 | a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)), | 117 | a16 = (zd_addr_t *) kmalloc(count16 * (sizeof(zd_addr_t) + sizeof(u16)), |
117 | GFP_NOFS); | 118 | GFP_KERNEL); |
118 | if (!a16) { | 119 | if (!a16) { |
119 | dev_dbg_f(zd_chip_dev(chip), | 120 | dev_dbg_f(zd_chip_dev(chip), |
120 | "error ENOMEM in allocation of a16\n"); | 121 | "error ENOMEM in allocation of a16\n"); |
@@ -163,7 +164,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs, | |||
163 | 164 | ||
164 | /* Allocate a single memory block for values and addresses. */ | 165 | /* Allocate a single memory block for values and addresses. */ |
165 | count16 = 2*count; | 166 | count16 = 2*count; |
166 | ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_NOFS); | 167 | ioreqs16 = kmalloc(count16 * sizeof(struct zd_ioreq16), GFP_KERNEL); |
167 | if (!ioreqs16) { | 168 | if (!ioreqs16) { |
168 | r = -ENOMEM; | 169 | r = -ENOMEM; |
169 | dev_dbg_f(zd_chip_dev(chip), | 170 | dev_dbg_f(zd_chip_dev(chip), |
@@ -614,16 +615,24 @@ static int patch_cr157(struct zd_chip *chip) | |||
614 | * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge | 615 | * Vendor driver says: for FCC regulation, enabled per HWFeature 6M band edge |
615 | * bit (for AL2230, AL2230S) | 616 | * bit (for AL2230, AL2230S) |
616 | */ | 617 | */ |
617 | static int patch_6m_band_edge(struct zd_chip *chip, int channel) | 618 | static int patch_6m_band_edge(struct zd_chip *chip, u8 channel) |
619 | { | ||
620 | ZD_ASSERT(mutex_is_locked(&chip->mutex)); | ||
621 | if (!chip->patch_6m_band_edge) | ||
622 | return 0; | ||
623 | |||
624 | return zd_rf_patch_6m_band_edge(&chip->rf, channel); | ||
625 | } | ||
626 | |||
627 | /* Generic implementation of 6M band edge patching, used by most RFs via | ||
628 | * zd_rf_generic_patch_6m() */ | ||
629 | int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel) | ||
618 | { | 630 | { |
619 | struct zd_ioreq16 ioreqs[] = { | 631 | struct zd_ioreq16 ioreqs[] = { |
620 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 632 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, |
621 | { CR47, 0x1e }, | 633 | { CR47, 0x1e }, |
622 | }; | 634 | }; |
623 | 635 | ||
624 | if (!chip->patch_6m_band_edge || !chip->rf.patch_6m_band_edge) | ||
625 | return 0; | ||
626 | |||
627 | /* FIXME: Channel 11 is not the edge for all regulatory domains. */ | 636 | /* FIXME: Channel 11 is not the edge for all regulatory domains. */ |
628 | if (channel == 1 || channel == 11) | 637 | if (channel == 1 || channel == 11) |
629 | ioreqs[0].value = 0x12; | 638 | ioreqs[0].value = 0x12; |
@@ -683,17 +692,17 @@ static int zd1211_hw_reset_phy(struct zd_chip *chip) | |||
683 | { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, | 692 | { CR111, 0x27 }, { CR112, 0x27 }, { CR113, 0x27 }, |
684 | { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, | 693 | { CR114, 0x27 }, { CR115, 0x26 }, { CR116, 0x24 }, |
685 | { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, | 694 | { CR117, 0xfc }, { CR118, 0xfa }, { CR120, 0x4f }, |
686 | { CR123, 0x27 }, { CR125, 0xaa }, { CR127, 0x03 }, | 695 | { CR125, 0xaa }, { CR127, 0x03 }, { CR128, 0x14 }, |
687 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 696 | { CR129, 0x12 }, { CR130, 0x10 }, { CR131, 0x0C }, |
688 | { CR131, 0x0C }, { CR136, 0xdf }, { CR137, 0x40 }, | 697 | { CR136, 0xdf }, { CR137, 0x40 }, { CR138, 0xa0 }, |
689 | { CR138, 0xa0 }, { CR139, 0xb0 }, { CR140, 0x99 }, | 698 | { CR139, 0xb0 }, { CR140, 0x99 }, { CR141, 0x82 }, |
690 | { CR141, 0x82 }, { CR142, 0x54 }, { CR143, 0x1c }, | 699 | { CR142, 0x54 }, { CR143, 0x1c }, { CR144, 0x6c }, |
691 | { CR144, 0x6c }, { CR147, 0x07 }, { CR148, 0x4c }, | 700 | { CR147, 0x07 }, { CR148, 0x4c }, { CR149, 0x50 }, |
692 | { CR149, 0x50 }, { CR150, 0x0e }, { CR151, 0x18 }, | 701 | { CR150, 0x0e }, { CR151, 0x18 }, { CR160, 0xfe }, |
693 | { CR160, 0xfe }, { CR161, 0xee }, { CR162, 0xaa }, | 702 | { CR161, 0xee }, { CR162, 0xaa }, { CR163, 0xfa }, |
694 | { CR163, 0xfa }, { CR164, 0xfa }, { CR165, 0xea }, | 703 | { CR164, 0xfa }, { CR165, 0xea }, { CR166, 0xbe }, |
695 | { CR166, 0xbe }, { CR167, 0xbe }, { CR168, 0x6a }, | 704 | { CR167, 0xbe }, { CR168, 0x6a }, { CR169, 0xba }, |
696 | { CR169, 0xba }, { CR170, 0xba }, { CR171, 0xba }, | 705 | { CR170, 0xba }, { CR171, 0xba }, |
697 | /* Note: CR204 must lead the CR203 */ | 706 | /* Note: CR204 must lead the CR203 */ |
698 | { CR204, 0x7d }, | 707 | { CR204, 0x7d }, |
699 | { }, | 708 | { }, |
diff --git a/drivers/net/wireless/zd1211rw/zd_chip.h b/drivers/net/wireless/zd1211rw/zd_chip.h index e57ed75d9425..ce0a5f6da0d2 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.h +++ b/drivers/net/wireless/zd1211rw/zd_chip.h | |||
@@ -833,6 +833,7 @@ int zd_chip_enable_rx(struct zd_chip *chip); | |||
833 | void zd_chip_disable_rx(struct zd_chip *chip); | 833 | void zd_chip_disable_rx(struct zd_chip *chip); |
834 | int zd_chip_enable_hwint(struct zd_chip *chip); | 834 | int zd_chip_enable_hwint(struct zd_chip *chip); |
835 | int zd_chip_disable_hwint(struct zd_chip *chip); | 835 | int zd_chip_disable_hwint(struct zd_chip *chip); |
836 | int zd_chip_generic_patch_6m_band(struct zd_chip *chip, int channel); | ||
836 | 837 | ||
837 | int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, | 838 | int zd_chip_set_rts_cts_rate_locked(struct zd_chip *chip, |
838 | u8 rts_rate, int preamble); | 839 | u8 rts_rate, int preamble); |
diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 4c5f78eac349..6753d240c168 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c | |||
@@ -156,17 +156,8 @@ void zd_mac_clear(struct zd_mac *mac) | |||
156 | static int reset_mode(struct zd_mac *mac) | 156 | static int reset_mode(struct zd_mac *mac) |
157 | { | 157 | { |
158 | struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); | 158 | struct ieee80211_device *ieee = zd_mac_to_ieee80211(mac); |
159 | struct zd_ioreq32 ioreqs[] = { | 159 | u32 filter = (ieee->iw_mode == IW_MODE_MONITOR) ? ~0 : STA_RX_FILTER; |
160 | { CR_RX_FILTER, STA_RX_FILTER }, | 160 | return zd_iowrite32(&mac->chip, CR_RX_FILTER, filter); |
161 | { CR_SNIFFER_ON, 0U }, | ||
162 | }; | ||
163 | |||
164 | if (ieee->iw_mode == IW_MODE_MONITOR) { | ||
165 | ioreqs[0].value = 0xffffffff; | ||
166 | ioreqs[1].value = 0x1; | ||
167 | } | ||
168 | |||
169 | return zd_iowrite32a(&mac->chip, ioreqs, ARRAY_SIZE(ioreqs)); | ||
170 | } | 161 | } |
171 | 162 | ||
172 | int zd_mac_open(struct net_device *netdev) | 163 | int zd_mac_open(struct net_device *netdev) |
@@ -974,14 +965,14 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee, | |||
974 | switch (ieee->iw_mode) { | 965 | switch (ieee->iw_mode) { |
975 | case IW_MODE_ADHOC: | 966 | case IW_MODE_ADHOC: |
976 | if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 || | 967 | if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != 0 || |
977 | memcmp(hdr->addr3, ieee->bssid, ETH_ALEN) != 0) | 968 | compare_ether_addr(hdr->addr3, ieee->bssid) != 0) |
978 | return 0; | 969 | return 0; |
979 | break; | 970 | break; |
980 | case IW_MODE_AUTO: | 971 | case IW_MODE_AUTO: |
981 | case IW_MODE_INFRA: | 972 | case IW_MODE_INFRA: |
982 | if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != | 973 | if ((fc & (IEEE80211_FCTL_TODS|IEEE80211_FCTL_FROMDS)) != |
983 | IEEE80211_FCTL_FROMDS || | 974 | IEEE80211_FCTL_FROMDS || |
984 | memcmp(hdr->addr2, ieee->bssid, ETH_ALEN) != 0) | 975 | compare_ether_addr(hdr->addr2, ieee->bssid) != 0) |
985 | return 0; | 976 | return 0; |
986 | break; | 977 | break; |
987 | default: | 978 | default: |
@@ -989,9 +980,9 @@ static int is_data_packet_for_us(struct ieee80211_device *ieee, | |||
989 | return 0; | 980 | return 0; |
990 | } | 981 | } |
991 | 982 | ||
992 | return memcmp(hdr->addr1, netdev->dev_addr, ETH_ALEN) == 0 || | 983 | return compare_ether_addr(hdr->addr1, netdev->dev_addr) == 0 || |
993 | (is_multicast_ether_addr(hdr->addr1) && | 984 | (is_multicast_ether_addr(hdr->addr1) && |
994 | memcmp(hdr->addr3, netdev->dev_addr, ETH_ALEN) != 0) || | 985 | compare_ether_addr(hdr->addr3, netdev->dev_addr) != 0) || |
995 | (netdev->flags & IFF_PROMISC); | 986 | (netdev->flags & IFF_PROMISC); |
996 | } | 987 | } |
997 | 988 | ||
@@ -1047,7 +1038,7 @@ static void update_qual_rssi(struct zd_mac *mac, | |||
1047 | hdr = (struct ieee80211_hdr_3addr *)buffer; | 1038 | hdr = (struct ieee80211_hdr_3addr *)buffer; |
1048 | if (length < offsetof(struct ieee80211_hdr_3addr, addr3)) | 1039 | if (length < offsetof(struct ieee80211_hdr_3addr, addr3)) |
1049 | return; | 1040 | return; |
1050 | if (memcmp(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid, ETH_ALEN) != 0) | 1041 | if (compare_ether_addr(hdr->addr2, zd_mac_to_ieee80211(mac)->bssid) != 0) |
1051 | return; | 1042 | return; |
1052 | 1043 | ||
1053 | spin_lock_irqsave(&mac->lock, flags); | 1044 | spin_lock_irqsave(&mac->lock, flags); |
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.c b/drivers/net/wireless/zd1211rw/zd_rf.c index f50cff3db916..549c23bcd6cc 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.c +++ b/drivers/net/wireless/zd1211rw/zd_rf.c | |||
@@ -23,7 +23,7 @@ | |||
23 | #include "zd_ieee80211.h" | 23 | #include "zd_ieee80211.h" |
24 | #include "zd_chip.h" | 24 | #include "zd_chip.h" |
25 | 25 | ||
26 | static const char *rfs[] = { | 26 | static const char * const rfs[] = { |
27 | [0] = "unknown RF0", | 27 | [0] = "unknown RF0", |
28 | [1] = "unknown RF1", | 28 | [1] = "unknown RF1", |
29 | [UW2451_RF] = "UW2451_RF", | 29 | [UW2451_RF] = "UW2451_RF", |
@@ -34,7 +34,7 @@ static const char *rfs[] = { | |||
34 | [AL2210_RF] = "AL2210_RF", | 34 | [AL2210_RF] = "AL2210_RF", |
35 | [MAXIM_NEW_RF] = "MAXIM_NEW_RF", | 35 | [MAXIM_NEW_RF] = "MAXIM_NEW_RF", |
36 | [UW2453_RF] = "UW2453_RF", | 36 | [UW2453_RF] = "UW2453_RF", |
37 | [AL2230S_RF] = "AL2230S_RF", | 37 | [UNKNOWN_A_RF] = "UNKNOWN_A_RF", |
38 | [RALINK_RF] = "RALINK_RF", | 38 | [RALINK_RF] = "RALINK_RF", |
39 | [INTERSIL_RF] = "INTERSIL_RF", | 39 | [INTERSIL_RF] = "INTERSIL_RF", |
40 | [RF2959_RF] = "RF2959_RF", | 40 | [RF2959_RF] = "RF2959_RF", |
@@ -154,3 +154,17 @@ int zd_switch_radio_off(struct zd_rf *rf) | |||
154 | r = t; | 154 | r = t; |
155 | return r; | 155 | return r; |
156 | } | 156 | } |
157 | |||
158 | int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel) | ||
159 | { | ||
160 | if (!rf->patch_6m_band_edge) | ||
161 | return 0; | ||
162 | |||
163 | return rf->patch_6m_band_edge(rf, channel); | ||
164 | } | ||
165 | |||
166 | int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel) | ||
167 | { | ||
168 | return zd_chip_generic_patch_6m_band(zd_rf_to_chip(rf), channel); | ||
169 | } | ||
170 | |||
diff --git a/drivers/net/wireless/zd1211rw/zd_rf.h b/drivers/net/wireless/zd1211rw/zd_rf.h index a57732eb69e1..aa9cc105ce60 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf.h +++ b/drivers/net/wireless/zd1211rw/zd_rf.h | |||
@@ -26,7 +26,7 @@ | |||
26 | #define AL2210_RF 0x7 | 26 | #define AL2210_RF 0x7 |
27 | #define MAXIM_NEW_RF 0x8 | 27 | #define MAXIM_NEW_RF 0x8 |
28 | #define UW2453_RF 0x9 | 28 | #define UW2453_RF 0x9 |
29 | #define AL2230S_RF 0xa | 29 | #define UNKNOWN_A_RF 0xa |
30 | #define RALINK_RF 0xb | 30 | #define RALINK_RF 0xb |
31 | #define INTERSIL_RF 0xc | 31 | #define INTERSIL_RF 0xc |
32 | #define RF2959_RF 0xd | 32 | #define RF2959_RF 0xd |
@@ -47,17 +47,13 @@ struct zd_rf { | |||
47 | u8 type; | 47 | u8 type; |
48 | 48 | ||
49 | u8 channel; | 49 | u8 channel; |
50 | /* | ||
51 | * Whether this RF should patch the 6M band edge | ||
52 | * (assuming E2P_POD agrees) | ||
53 | */ | ||
54 | u8 patch_6m_band_edge:1; | ||
55 | 50 | ||
56 | /* RF-specific functions */ | 51 | /* RF-specific functions */ |
57 | int (*init_hw)(struct zd_rf *rf); | 52 | int (*init_hw)(struct zd_rf *rf); |
58 | int (*set_channel)(struct zd_rf *rf, u8 channel); | 53 | int (*set_channel)(struct zd_rf *rf, u8 channel); |
59 | int (*switch_radio_on)(struct zd_rf *rf); | 54 | int (*switch_radio_on)(struct zd_rf *rf); |
60 | int (*switch_radio_off)(struct zd_rf *rf); | 55 | int (*switch_radio_off)(struct zd_rf *rf); |
56 | int (*patch_6m_band_edge)(struct zd_rf *rf, u8 channel); | ||
61 | }; | 57 | }; |
62 | 58 | ||
63 | const char *zd_rf_name(u8 type); | 59 | const char *zd_rf_name(u8 type); |
@@ -72,6 +68,9 @@ int zd_rf_set_channel(struct zd_rf *rf, u8 channel); | |||
72 | int zd_switch_radio_on(struct zd_rf *rf); | 68 | int zd_switch_radio_on(struct zd_rf *rf); |
73 | int zd_switch_radio_off(struct zd_rf *rf); | 69 | int zd_switch_radio_off(struct zd_rf *rf); |
74 | 70 | ||
71 | int zd_rf_patch_6m_band_edge(struct zd_rf *rf, u8 channel); | ||
72 | int zd_rf_generic_patch_6m(struct zd_rf *rf, u8 channel); | ||
73 | |||
75 | /* Functions for individual RF chips */ | 74 | /* Functions for individual RF chips */ |
76 | 75 | ||
77 | int zd_rf_init_rf2959(struct zd_rf *rf); | 76 | int zd_rf_init_rf2959(struct zd_rf *rf); |
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c index 5235a7827ac5..511392acfedf 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al2230.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al2230.c | |||
@@ -59,6 +59,18 @@ static const struct zd_ioreq16 zd1211b_ioreqs_shared_1[] = { | |||
59 | { CR240, 0x57 }, { CR9, 0xe0 }, | 59 | { CR240, 0x57 }, { CR9, 0xe0 }, |
60 | }; | 60 | }; |
61 | 61 | ||
62 | static const struct zd_ioreq16 ioreqs_init_al2230s[] = { | ||
63 | { CR47, 0x1e }, /* MARK_002 */ | ||
64 | { CR106, 0x22 }, | ||
65 | { CR107, 0x2a }, /* MARK_002 */ | ||
66 | { CR109, 0x13 }, /* MARK_002 */ | ||
67 | { CR118, 0xf8 }, /* MARK_002 */ | ||
68 | { CR119, 0x12 }, { CR122, 0xe0 }, | ||
69 | { CR128, 0x10 }, /* MARK_001 from 0xe->0x10 */ | ||
70 | { CR129, 0x0e }, /* MARK_001 from 0xd->0x0e */ | ||
71 | { CR130, 0x10 }, /* MARK_001 from 0xb->0x0d */ | ||
72 | }; | ||
73 | |||
62 | static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) | 74 | static int zd1211b_al2230_finalize_rf(struct zd_chip *chip) |
63 | { | 75 | { |
64 | int r; | 76 | int r; |
@@ -90,7 +102,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) | |||
90 | int r; | 102 | int r; |
91 | struct zd_chip *chip = zd_rf_to_chip(rf); | 103 | struct zd_chip *chip = zd_rf_to_chip(rf); |
92 | 104 | ||
93 | static const struct zd_ioreq16 ioreqs[] = { | 105 | static const struct zd_ioreq16 ioreqs_init[] = { |
94 | { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, | 106 | { CR15, 0x20 }, { CR23, 0x40 }, { CR24, 0x20 }, |
95 | { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, | 107 | { CR26, 0x11 }, { CR28, 0x3e }, { CR29, 0x00 }, |
96 | { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, | 108 | { CR44, 0x33 }, { CR106, 0x2a }, { CR107, 0x1a }, |
@@ -117,10 +129,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) | |||
117 | { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, | 129 | { CR119, 0x10 }, { CR120, 0x4f }, { CR121, 0x77 }, |
118 | { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, | 130 | { CR122, 0xe0 }, { CR137, 0x88 }, { CR252, 0xff }, |
119 | { CR253, 0xff }, | 131 | { CR253, 0xff }, |
132 | }; | ||
120 | 133 | ||
121 | /* These following happen separately in the vendor driver */ | 134 | static const struct zd_ioreq16 ioreqs_pll[] = { |
122 | { }, | ||
123 | |||
124 | /* shdnb(PLL_ON)=0 */ | 135 | /* shdnb(PLL_ON)=0 */ |
125 | { CR251, 0x2f }, | 136 | { CR251, 0x2f }, |
126 | /* shdnb(PLL_ON)=1 */ | 137 | /* shdnb(PLL_ON)=1 */ |
@@ -128,7 +139,7 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) | |||
128 | { CR138, 0x28 }, { CR203, 0x06 }, | 139 | { CR138, 0x28 }, { CR203, 0x06 }, |
129 | }; | 140 | }; |
130 | 141 | ||
131 | static const u32 rv[] = { | 142 | static const u32 rv1[] = { |
132 | /* Channel 1 */ | 143 | /* Channel 1 */ |
133 | 0x03f790, | 144 | 0x03f790, |
134 | 0x033331, | 145 | 0x033331, |
@@ -137,6 +148,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) | |||
137 | 0x0b3331, | 148 | 0x0b3331, |
138 | 0x03b812, | 149 | 0x03b812, |
139 | 0x00fff3, | 150 | 0x00fff3, |
151 | }; | ||
152 | |||
153 | static const u32 rv2[] = { | ||
140 | 0x000da4, | 154 | 0x000da4, |
141 | 0x0f4dc5, /* fix freq shift, 0x04edc5 */ | 155 | 0x0f4dc5, /* fix freq shift, 0x04edc5 */ |
142 | 0x0805b6, | 156 | 0x0805b6, |
@@ -148,8 +162,9 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) | |||
148 | 0x0bdffc, | 162 | 0x0bdffc, |
149 | 0x00000d, | 163 | 0x00000d, |
150 | 0x00500f, | 164 | 0x00500f, |
165 | }; | ||
151 | 166 | ||
152 | /* These writes happen separately in the vendor driver */ | 167 | static const u32 rv3[] = { |
153 | 0x00d00f, | 168 | 0x00d00f, |
154 | 0x004c0f, | 169 | 0x004c0f, |
155 | 0x00540f, | 170 | 0x00540f, |
@@ -157,11 +172,38 @@ static int zd1211_al2230_init_hw(struct zd_rf *rf) | |||
157 | 0x00500f, | 172 | 0x00500f, |
158 | }; | 173 | }; |
159 | 174 | ||
160 | r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 175 | r = zd_iowrite16a_locked(chip, ioreqs_init, ARRAY_SIZE(ioreqs_init)); |
161 | if (r) | 176 | if (r) |
162 | return r; | 177 | return r; |
163 | 178 | ||
164 | r = zd_rfwritev_locked(chip, rv, ARRAY_SIZE(rv), RF_RV_BITS); | 179 | if (chip->al2230s_bit) { |
180 | r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, | ||
181 | ARRAY_SIZE(ioreqs_init_al2230s)); | ||
182 | if (r) | ||
183 | return r; | ||
184 | } | ||
185 | |||
186 | r = zd_rfwritev_locked(chip, rv1, ARRAY_SIZE(rv1), RF_RV_BITS); | ||
187 | if (r) | ||
188 | return r; | ||
189 | |||
190 | /* improve band edge for AL2230S */ | ||
191 | if (chip->al2230s_bit) | ||
192 | r = zd_rfwrite_locked(chip, 0x000824, RF_RV_BITS); | ||
193 | else | ||
194 | r = zd_rfwrite_locked(chip, 0x0005a4, RF_RV_BITS); | ||
195 | if (r) | ||
196 | return r; | ||
197 | |||
198 | r = zd_rfwritev_locked(chip, rv2, ARRAY_SIZE(rv2), RF_RV_BITS); | ||
199 | if (r) | ||
200 | return r; | ||
201 | |||
202 | r = zd_iowrite16a_locked(chip, ioreqs_pll, ARRAY_SIZE(ioreqs_pll)); | ||
203 | if (r) | ||
204 | return r; | ||
205 | |||
206 | r = zd_rfwritev_locked(chip, rv3, ARRAY_SIZE(rv3), RF_RV_BITS); | ||
165 | if (r) | 207 | if (r) |
166 | return r; | 208 | return r; |
167 | 209 | ||
@@ -227,7 +269,9 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) | |||
227 | 0x481dc0, | 269 | 0x481dc0, |
228 | 0xcfff00, | 270 | 0xcfff00, |
229 | 0x25a000, | 271 | 0x25a000, |
272 | }; | ||
230 | 273 | ||
274 | static const u32 rv2[] = { | ||
231 | /* To improve AL2230 yield, improve phase noise, 4713 */ | 275 | /* To improve AL2230 yield, improve phase noise, 4713 */ |
232 | 0x25a000, | 276 | 0x25a000, |
233 | 0xa3b2f0, | 277 | 0xa3b2f0, |
@@ -250,7 +294,7 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) | |||
250 | { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ | 294 | { CR251, 0x7f }, /* shdnb(PLL_ON)=1 */ |
251 | }; | 295 | }; |
252 | 296 | ||
253 | static const u32 rv2[] = { | 297 | static const u32 rv3[] = { |
254 | /* To improve AL2230 yield, 4713 */ | 298 | /* To improve AL2230 yield, 4713 */ |
255 | 0xf01b00, | 299 | 0xf01b00, |
256 | 0xf01e00, | 300 | 0xf01e00, |
@@ -269,18 +313,37 @@ static int zd1211b_al2230_init_hw(struct zd_rf *rf) | |||
269 | r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1)); | 313 | r = zd_iowrite16a_locked(chip, ioreqs1, ARRAY_SIZE(ioreqs1)); |
270 | if (r) | 314 | if (r) |
271 | return r; | 315 | return r; |
316 | |||
317 | if (chip->al2230s_bit) { | ||
318 | r = zd_iowrite16a_locked(chip, ioreqs_init_al2230s, | ||
319 | ARRAY_SIZE(ioreqs_init_al2230s)); | ||
320 | if (r) | ||
321 | return r; | ||
322 | } | ||
323 | |||
272 | r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3); | 324 | r = zd_rfwritev_cr_locked(chip, zd1211b_al2230_table[0], 3); |
273 | if (r) | 325 | if (r) |
274 | return r; | 326 | return r; |
275 | r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1)); | 327 | r = zd_rfwritev_cr_locked(chip, rv1, ARRAY_SIZE(rv1)); |
276 | if (r) | 328 | if (r) |
277 | return r; | 329 | return r; |
278 | r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); | 330 | |
331 | if (chip->al2230s_bit) | ||
332 | r = zd_rfwrite_locked(chip, 0x241000, RF_RV_BITS); | ||
333 | else | ||
334 | r = zd_rfwrite_locked(chip, 0x25a000, RF_RV_BITS); | ||
279 | if (r) | 335 | if (r) |
280 | return r; | 336 | return r; |
337 | |||
281 | r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2)); | 338 | r = zd_rfwritev_cr_locked(chip, rv2, ARRAY_SIZE(rv2)); |
282 | if (r) | 339 | if (r) |
283 | return r; | 340 | return r; |
341 | r = zd_iowrite16a_locked(chip, ioreqs2, ARRAY_SIZE(ioreqs2)); | ||
342 | if (r) | ||
343 | return r; | ||
344 | r = zd_rfwritev_cr_locked(chip, rv3, ARRAY_SIZE(rv3)); | ||
345 | if (r) | ||
346 | return r; | ||
284 | r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3)); | 347 | r = zd_iowrite16a_locked(chip, ioreqs3, ARRAY_SIZE(ioreqs3)); |
285 | if (r) | 348 | if (r) |
286 | return r; | 349 | return r; |
@@ -358,12 +421,6 @@ int zd_rf_init_al2230(struct zd_rf *rf) | |||
358 | { | 421 | { |
359 | struct zd_chip *chip = zd_rf_to_chip(rf); | 422 | struct zd_chip *chip = zd_rf_to_chip(rf); |
360 | 423 | ||
361 | if (chip->al2230s_bit) { | ||
362 | dev_err(zd_chip_dev(chip), "AL2230S devices are not yet " | ||
363 | "supported by this driver.\n"); | ||
364 | return -ENODEV; | ||
365 | } | ||
366 | |||
367 | rf->switch_radio_off = al2230_switch_radio_off; | 424 | rf->switch_radio_off = al2230_switch_radio_off; |
368 | if (chip->is_zd1211b) { | 425 | if (chip->is_zd1211b) { |
369 | rf->init_hw = zd1211b_al2230_init_hw; | 426 | rf->init_hw = zd1211b_al2230_init_hw; |
@@ -374,6 +431,6 @@ int zd_rf_init_al2230(struct zd_rf *rf) | |||
374 | rf->set_channel = zd1211_al2230_set_channel; | 431 | rf->set_channel = zd1211_al2230_set_channel; |
375 | rf->switch_radio_on = zd1211_al2230_switch_radio_on; | 432 | rf->switch_radio_on = zd1211_al2230_switch_radio_on; |
376 | } | 433 | } |
377 | rf->patch_6m_band_edge = 1; | 434 | rf->patch_6m_band_edge = zd_rf_generic_patch_6m; |
378 | return 0; | 435 | return 0; |
379 | } | 436 | } |
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c index a289f95187ec..5e5e9ddc6a74 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_al7230b.c | |||
@@ -51,9 +51,52 @@ static const u32 std_rv[] = { | |||
51 | 0xd8c010, | 51 | 0xd8c010, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static int al7230b_init_hw(struct zd_rf *rf) | 54 | static const u32 rv_init1[] = { |
55 | 0x3c9000, | ||
56 | 0xbfffff, | ||
57 | 0x700000, | ||
58 | 0xf15d58, | ||
59 | }; | ||
60 | |||
61 | static const u32 rv_init2[] = { | ||
62 | 0xf15d59, | ||
63 | 0xf15d5c, | ||
64 | 0xf15d58, | ||
65 | }; | ||
66 | |||
67 | static const struct zd_ioreq16 ioreqs_sw[] = { | ||
68 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | ||
69 | { CR38, 0x38 }, { CR136, 0xdf }, | ||
70 | }; | ||
71 | |||
72 | static int zd1211b_al7230b_finalize(struct zd_chip *chip) | ||
55 | { | 73 | { |
56 | int i, r; | 74 | int r; |
75 | static const struct zd_ioreq16 ioreqs[] = { | ||
76 | { CR80, 0x30 }, { CR81, 0x30 }, { CR79, 0x58 }, | ||
77 | { CR12, 0xf0 }, { CR77, 0x1b }, { CR78, 0x58 }, | ||
78 | { CR203, 0x04 }, | ||
79 | { }, | ||
80 | { CR240, 0x80 }, | ||
81 | }; | ||
82 | |||
83 | r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | ||
84 | if (r) | ||
85 | return r; | ||
86 | |||
87 | if (chip->new_phy_layout) { | ||
88 | /* antenna selection? */ | ||
89 | r = zd_iowrite16_locked(chip, 0xe5, CR9); | ||
90 | if (r) | ||
91 | return r; | ||
92 | } | ||
93 | |||
94 | return zd_iowrite16_locked(chip, 0x04, CR203); | ||
95 | } | ||
96 | |||
97 | static int zd1211_al7230b_init_hw(struct zd_rf *rf) | ||
98 | { | ||
99 | int r; | ||
57 | struct zd_chip *chip = zd_rf_to_chip(rf); | 100 | struct zd_chip *chip = zd_rf_to_chip(rf); |
58 | 101 | ||
59 | /* All of these writes are identical to AL2230 unless otherwise | 102 | /* All of these writes are identical to AL2230 unless otherwise |
@@ -117,39 +160,136 @@ static int al7230b_init_hw(struct zd_rf *rf) | |||
117 | }; | 160 | }; |
118 | 161 | ||
119 | static const struct zd_ioreq16 ioreqs_2[] = { | 162 | static const struct zd_ioreq16 ioreqs_2[] = { |
120 | /* PLL_ON */ | 163 | { CR251, 0x3f }, /* PLL_ON */ |
121 | { CR251, 0x3f }, | ||
122 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | 164 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, |
123 | { CR38, 0x38 }, { CR136, 0xdf }, | 165 | { CR38, 0x38 }, { CR136, 0xdf }, |
124 | }; | 166 | }; |
125 | 167 | ||
126 | r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); | 168 | r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); |
127 | if (r) | 169 | if (r) |
128 | return r; | 170 | return r; |
129 | 171 | ||
130 | r = zd_rfwrite_cr_locked(chip, 0x09ec04); | 172 | r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0])); |
131 | if (r) | 173 | if (r) |
132 | return r; | 174 | return r; |
133 | r = zd_rfwrite_cr_locked(chip, 0x8cccc8); | 175 | |
176 | r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); | ||
134 | if (r) | 177 | if (r) |
135 | return r; | 178 | return r; |
136 | 179 | ||
137 | for (i = 0; i < ARRAY_SIZE(std_rv); i++) { | 180 | r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1)); |
138 | r = zd_rfwrite_cr_locked(chip, std_rv[i]); | 181 | if (r) |
139 | if (r) | 182 | return r; |
140 | return r; | ||
141 | } | ||
142 | 183 | ||
143 | r = zd_rfwrite_cr_locked(chip, 0x3c9000); | 184 | r = zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2)); |
144 | if (r) | 185 | if (r) |
145 | return r; | 186 | return r; |
146 | r = zd_rfwrite_cr_locked(chip, 0xbfffff); | 187 | |
188 | r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2)); | ||
147 | if (r) | 189 | if (r) |
148 | return r; | 190 | return r; |
149 | r = zd_rfwrite_cr_locked(chip, 0x700000); | 191 | |
192 | r = zd_iowrite16_locked(chip, 0x06, CR203); | ||
150 | if (r) | 193 | if (r) |
151 | return r; | 194 | return r; |
152 | r = zd_rfwrite_cr_locked(chip, 0xf15d58); | 195 | r = zd_iowrite16_locked(chip, 0x80, CR240); |
196 | if (r) | ||
197 | return r; | ||
198 | |||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int zd1211b_al7230b_init_hw(struct zd_rf *rf) | ||
203 | { | ||
204 | int r; | ||
205 | struct zd_chip *chip = zd_rf_to_chip(rf); | ||
206 | |||
207 | static const struct zd_ioreq16 ioreqs_1[] = { | ||
208 | { CR240, 0x57 }, { CR9, 0x9 }, | ||
209 | { }, | ||
210 | { CR10, 0x8b }, { CR15, 0x20 }, | ||
211 | { CR17, 0x2B }, /* for newest (3rd cut) AL2230 */ | ||
212 | { CR20, 0x10 }, /* 4N25->Stone Request */ | ||
213 | { CR23, 0x40 }, { CR24, 0x20 }, { CR26, 0x93 }, | ||
214 | { CR28, 0x3e }, { CR29, 0x00 }, | ||
215 | { CR33, 0x28 }, /* 5613 */ | ||
216 | { CR34, 0x30 }, | ||
217 | { CR35, 0x3e }, /* for newest (3rd cut) AL2230 */ | ||
218 | { CR41, 0x24 }, { CR44, 0x32 }, | ||
219 | { CR46, 0x99 }, /* for newest (3rd cut) AL2230 */ | ||
220 | { CR47, 0x1e }, | ||
221 | |||
222 | /* ZD1215 5610 */ | ||
223 | { CR48, 0x00 }, { CR49, 0x00 }, { CR51, 0x01 }, | ||
224 | { CR52, 0x80 }, { CR53, 0x7e }, { CR65, 0x00 }, | ||
225 | { CR66, 0x00 }, { CR67, 0x00 }, { CR68, 0x00 }, | ||
226 | { CR69, 0x28 }, | ||
227 | |||
228 | { CR79, 0x58 }, { CR80, 0x30 }, { CR81, 0x30 }, | ||
229 | { CR87, 0x0A }, { CR89, 0x04 }, | ||
230 | { CR90, 0x58 }, /* 5112 */ | ||
231 | { CR91, 0x00 }, /* 5613 */ | ||
232 | { CR92, 0x0a }, | ||
233 | { CR98, 0x8d }, /* 4804, for 1212 new algorithm */ | ||
234 | { CR99, 0x00 }, { CR100, 0x02 }, { CR101, 0x13 }, | ||
235 | { CR102, 0x27 }, | ||
236 | { CR106, 0x20 }, /* change to 0x24 for AL7230B */ | ||
237 | { CR109, 0x13 }, /* 4804, for 1212 new algorithm */ | ||
238 | { CR112, 0x1f }, | ||
239 | }; | ||
240 | |||
241 | static const struct zd_ioreq16 ioreqs_new_phy[] = { | ||
242 | { CR107, 0x28 }, | ||
243 | { CR110, 0x1f }, /* 5127, 0x13->0x1f */ | ||
244 | { CR111, 0x1f }, /* 0x13 to 0x1f for AL7230B */ | ||
245 | { CR116, 0x2a }, { CR118, 0xfa }, { CR119, 0x12 }, | ||
246 | { CR121, 0x6c }, /* 5613 */ | ||
247 | }; | ||
248 | |||
249 | static const struct zd_ioreq16 ioreqs_old_phy[] = { | ||
250 | { CR107, 0x24 }, | ||
251 | { CR110, 0x13 }, /* 5127, 0x13->0x1f */ | ||
252 | { CR111, 0x13 }, /* 0x13 to 0x1f for AL7230B */ | ||
253 | { CR116, 0x24 }, { CR118, 0xfc }, { CR119, 0x11 }, | ||
254 | { CR121, 0x6a }, /* 5613 */ | ||
255 | }; | ||
256 | |||
257 | static const struct zd_ioreq16 ioreqs_2[] = { | ||
258 | { CR113, 0x27 }, { CR114, 0x27 }, { CR115, 0x24 }, | ||
259 | { CR117, 0xfa }, { CR120, 0x4f }, | ||
260 | { CR122, 0xfc }, /* E0->FCh at 4901 */ | ||
261 | { CR123, 0x57 }, /* 5613 */ | ||
262 | { CR125, 0xad }, /* 4804, for 1212 new algorithm */ | ||
263 | { CR126, 0x6c }, /* 5613 */ | ||
264 | { CR127, 0x03 }, /* 4804, for 1212 new algorithm */ | ||
265 | { CR130, 0x10 }, | ||
266 | { CR131, 0x00 }, /* 5112 */ | ||
267 | { CR137, 0x50 }, /* 5613 */ | ||
268 | { CR138, 0xa8 }, /* 5112 */ | ||
269 | { CR144, 0xac }, /* 5613 */ | ||
270 | { CR148, 0x40 }, /* 5112 */ | ||
271 | { CR149, 0x40 }, /* 4O07, 50->40 */ | ||
272 | { CR150, 0x1a }, /* 5112, 0C->1A */ | ||
273 | { CR252, 0x34 }, { CR253, 0x34 }, | ||
274 | { CR251, 0x2f }, /* PLL_OFF */ | ||
275 | }; | ||
276 | |||
277 | static const struct zd_ioreq16 ioreqs_3[] = { | ||
278 | { CR251, 0x7f }, /* PLL_ON */ | ||
279 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | ||
280 | { CR38, 0x38 }, { CR136, 0xdf }, | ||
281 | }; | ||
282 | |||
283 | r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); | ||
284 | if (r) | ||
285 | return r; | ||
286 | |||
287 | if (chip->new_phy_layout) | ||
288 | r = zd_iowrite16a_locked(chip, ioreqs_new_phy, | ||
289 | ARRAY_SIZE(ioreqs_new_phy)); | ||
290 | else | ||
291 | r = zd_iowrite16a_locked(chip, ioreqs_old_phy, | ||
292 | ARRAY_SIZE(ioreqs_old_phy)); | ||
153 | if (r) | 293 | if (r) |
154 | return r; | 294 | return r; |
155 | 295 | ||
@@ -157,38 +297,36 @@ static int al7230b_init_hw(struct zd_rf *rf) | |||
157 | if (r) | 297 | if (r) |
158 | return r; | 298 | return r; |
159 | 299 | ||
160 | r = zd_rfwrite_cr_locked(chip, 0xf15d59); | 300 | r = zd_rfwritev_cr_locked(chip, chan_rv[0], ARRAY_SIZE(chan_rv[0])); |
161 | if (r) | 301 | if (r) |
162 | return r; | 302 | return r; |
163 | r = zd_rfwrite_cr_locked(chip, 0xf15d5c); | 303 | |
304 | r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); | ||
164 | if (r) | 305 | if (r) |
165 | return r; | 306 | return r; |
166 | r = zd_rfwrite_cr_locked(chip, 0xf15d58); | 307 | |
308 | r = zd_rfwritev_cr_locked(chip, rv_init1, ARRAY_SIZE(rv_init1)); | ||
167 | if (r) | 309 | if (r) |
168 | return r; | 310 | return r; |
169 | 311 | ||
170 | r = zd_iowrite16_locked(chip, 0x06, CR203); | 312 | r = zd_iowrite16a_locked(chip, ioreqs_3, ARRAY_SIZE(ioreqs_3)); |
171 | if (r) | 313 | if (r) |
172 | return r; | 314 | return r; |
173 | r = zd_iowrite16_locked(chip, 0x80, CR240); | 315 | |
316 | r = zd_rfwritev_cr_locked(chip, rv_init2, ARRAY_SIZE(rv_init2)); | ||
174 | if (r) | 317 | if (r) |
175 | return r; | 318 | return r; |
176 | 319 | ||
177 | return 0; | 320 | return zd1211b_al7230b_finalize(chip); |
178 | } | 321 | } |
179 | 322 | ||
180 | static int al7230b_set_channel(struct zd_rf *rf, u8 channel) | 323 | static int zd1211_al7230b_set_channel(struct zd_rf *rf, u8 channel) |
181 | { | 324 | { |
182 | int i, r; | 325 | int r; |
183 | const u32 *rv = chan_rv[channel-1]; | 326 | const u32 *rv = chan_rv[channel-1]; |
184 | struct zd_chip *chip = zd_rf_to_chip(rf); | 327 | struct zd_chip *chip = zd_rf_to_chip(rf); |
185 | 328 | ||
186 | struct zd_ioreq16 ioreqs_1[] = { | 329 | static const struct zd_ioreq16 ioreqs[] = { |
187 | { CR128, 0x14 }, { CR129, 0x12 }, { CR130, 0x10 }, | ||
188 | { CR38, 0x38 }, { CR136, 0xdf }, | ||
189 | }; | ||
190 | |||
191 | struct zd_ioreq16 ioreqs_2[] = { | ||
192 | /* PLL_ON */ | 330 | /* PLL_ON */ |
193 | { CR251, 0x3f }, | 331 | { CR251, 0x3f }, |
194 | { CR203, 0x06 }, { CR240, 0x08 }, | 332 | { CR203, 0x06 }, { CR240, 0x08 }, |
@@ -203,11 +341,9 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel) | |||
203 | if (r) | 341 | if (r) |
204 | return r; | 342 | return r; |
205 | 343 | ||
206 | for (i = 0; i < ARRAY_SIZE(std_rv); i++) { | 344 | r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); |
207 | r = zd_rfwrite_cr_locked(chip, std_rv[i]); | 345 | if (r) |
208 | if (r) | 346 | return r; |
209 | return r; | ||
210 | } | ||
211 | 347 | ||
212 | r = zd_rfwrite_cr_locked(chip, 0x3c9000); | 348 | r = zd_rfwrite_cr_locked(chip, 0x3c9000); |
213 | if (r) | 349 | if (r) |
@@ -216,24 +352,69 @@ static int al7230b_set_channel(struct zd_rf *rf, u8 channel) | |||
216 | if (r) | 352 | if (r) |
217 | return r; | 353 | return r; |
218 | 354 | ||
219 | r = zd_iowrite16a_locked(chip, ioreqs_1, ARRAY_SIZE(ioreqs_1)); | 355 | r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw)); |
220 | if (r) | 356 | if (r) |
221 | return r; | 357 | return r; |
222 | 358 | ||
223 | for (i = 0; i < 2; i++) { | 359 | r = zd_rfwritev_cr_locked(chip, rv, 2); |
224 | r = zd_rfwrite_cr_locked(chip, rv[i]); | 360 | if (r) |
225 | if (r) | 361 | return r; |
226 | return r; | ||
227 | } | ||
228 | 362 | ||
229 | r = zd_rfwrite_cr_locked(chip, 0x3c9000); | 363 | r = zd_rfwrite_cr_locked(chip, 0x3c9000); |
230 | if (r) | 364 | if (r) |
231 | return r; | 365 | return r; |
232 | 366 | ||
233 | return zd_iowrite16a_locked(chip, ioreqs_2, ARRAY_SIZE(ioreqs_2)); | 367 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
234 | } | 368 | } |
235 | 369 | ||
236 | static int al7230b_switch_radio_on(struct zd_rf *rf) | 370 | static int zd1211b_al7230b_set_channel(struct zd_rf *rf, u8 channel) |
371 | { | ||
372 | int r; | ||
373 | const u32 *rv = chan_rv[channel-1]; | ||
374 | struct zd_chip *chip = zd_rf_to_chip(rf); | ||
375 | |||
376 | r = zd_iowrite16_locked(chip, 0x57, CR240); | ||
377 | if (r) | ||
378 | return r; | ||
379 | r = zd_iowrite16_locked(chip, 0xe4, CR9); | ||
380 | if (r) | ||
381 | return r; | ||
382 | |||
383 | /* PLL_OFF */ | ||
384 | r = zd_iowrite16_locked(chip, 0x2f, CR251); | ||
385 | if (r) | ||
386 | return r; | ||
387 | r = zd_rfwritev_cr_locked(chip, std_rv, ARRAY_SIZE(std_rv)); | ||
388 | if (r) | ||
389 | return r; | ||
390 | |||
391 | r = zd_rfwrite_cr_locked(chip, 0x3c9000); | ||
392 | if (r) | ||
393 | return r; | ||
394 | r = zd_rfwrite_cr_locked(chip, 0xf15d58); | ||
395 | if (r) | ||
396 | return r; | ||
397 | |||
398 | r = zd_iowrite16a_locked(chip, ioreqs_sw, ARRAY_SIZE(ioreqs_sw)); | ||
399 | if (r) | ||
400 | return r; | ||
401 | |||
402 | r = zd_rfwritev_cr_locked(chip, rv, 2); | ||
403 | if (r) | ||
404 | return r; | ||
405 | |||
406 | r = zd_rfwrite_cr_locked(chip, 0x3c9000); | ||
407 | if (r) | ||
408 | return r; | ||
409 | |||
410 | r = zd_iowrite16_locked(chip, 0x7f, CR251); | ||
411 | if (r) | ||
412 | return r; | ||
413 | |||
414 | return zd1211b_al7230b_finalize(chip); | ||
415 | } | ||
416 | |||
417 | static int zd1211_al7230b_switch_radio_on(struct zd_rf *rf) | ||
237 | { | 418 | { |
238 | struct zd_chip *chip = zd_rf_to_chip(rf); | 419 | struct zd_chip *chip = zd_rf_to_chip(rf); |
239 | static const struct zd_ioreq16 ioreqs[] = { | 420 | static const struct zd_ioreq16 ioreqs[] = { |
@@ -244,6 +425,17 @@ static int al7230b_switch_radio_on(struct zd_rf *rf) | |||
244 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 425 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
245 | } | 426 | } |
246 | 427 | ||
428 | static int zd1211b_al7230b_switch_radio_on(struct zd_rf *rf) | ||
429 | { | ||
430 | struct zd_chip *chip = zd_rf_to_chip(rf); | ||
431 | static const struct zd_ioreq16 ioreqs[] = { | ||
432 | { CR11, 0x00 }, | ||
433 | { CR251, 0x7f }, | ||
434 | }; | ||
435 | |||
436 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | ||
437 | } | ||
438 | |||
247 | static int al7230b_switch_radio_off(struct zd_rf *rf) | 439 | static int al7230b_switch_radio_off(struct zd_rf *rf) |
248 | { | 440 | { |
249 | struct zd_chip *chip = zd_rf_to_chip(rf); | 441 | struct zd_chip *chip = zd_rf_to_chip(rf); |
@@ -255,20 +447,45 @@ static int al7230b_switch_radio_off(struct zd_rf *rf) | |||
255 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | 447 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); |
256 | } | 448 | } |
257 | 449 | ||
450 | /* ZD1211B+AL7230B 6m band edge patching differs slightly from other | ||
451 | * configurations */ | ||
452 | static int zd1211b_al7230b_patch_6m(struct zd_rf *rf, u8 channel) | ||
453 | { | ||
454 | struct zd_chip *chip = zd_rf_to_chip(rf); | ||
455 | struct zd_ioreq16 ioreqs[] = { | ||
456 | { CR128, 0x14 }, { CR129, 0x12 }, | ||
457 | }; | ||
458 | |||
459 | /* FIXME: Channel 11 is not the edge for all regulatory domains. */ | ||
460 | if (channel == 1) { | ||
461 | ioreqs[0].value = 0x0e; | ||
462 | ioreqs[1].value = 0x10; | ||
463 | } else if (channel == 11) { | ||
464 | ioreqs[0].value = 0x10; | ||
465 | ioreqs[1].value = 0x10; | ||
466 | } | ||
467 | |||
468 | dev_dbg_f(zd_chip_dev(chip), "patching for channel %d\n", channel); | ||
469 | return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs)); | ||
470 | } | ||
471 | |||
258 | int zd_rf_init_al7230b(struct zd_rf *rf) | 472 | int zd_rf_init_al7230b(struct zd_rf *rf) |
259 | { | 473 | { |
260 | struct zd_chip *chip = zd_rf_to_chip(rf); | 474 | struct zd_chip *chip = zd_rf_to_chip(rf); |
261 | 475 | ||
262 | if (chip->is_zd1211b) { | 476 | if (chip->is_zd1211b) { |
263 | dev_err(zd_chip_dev(chip), "AL7230B is currently not " | 477 | rf->init_hw = zd1211b_al7230b_init_hw; |
264 | "supported for ZD1211B devices\n"); | 478 | rf->switch_radio_on = zd1211b_al7230b_switch_radio_on; |
265 | return -ENODEV; | 479 | rf->set_channel = zd1211b_al7230b_set_channel; |
480 | rf->patch_6m_band_edge = zd1211b_al7230b_patch_6m; | ||
481 | } else { | ||
482 | rf->init_hw = zd1211_al7230b_init_hw; | ||
483 | rf->switch_radio_on = zd1211_al7230b_switch_radio_on; | ||
484 | rf->set_channel = zd1211_al7230b_set_channel; | ||
485 | rf->patch_6m_band_edge = zd_rf_generic_patch_6m; | ||
266 | } | 486 | } |
267 | 487 | ||
268 | rf->init_hw = al7230b_init_hw; | ||
269 | rf->set_channel = al7230b_set_channel; | ||
270 | rf->switch_radio_on = al7230b_switch_radio_on; | ||
271 | rf->switch_radio_off = al7230b_switch_radio_off; | 488 | rf->switch_radio_off = al7230b_switch_radio_off; |
272 | rf->patch_6m_band_edge = 1; | 489 | |
273 | return 0; | 490 | return 0; |
274 | } | 491 | } |
diff --git a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c index 58247271cc24..2d736bdf707c 100644 --- a/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c +++ b/drivers/net/wireless/zd1211rw/zd_rf_rf2959.c | |||
@@ -21,7 +21,7 @@ | |||
21 | #include "zd_usb.h" | 21 | #include "zd_usb.h" |
22 | #include "zd_chip.h" | 22 | #include "zd_chip.h" |
23 | 23 | ||
24 | static u32 rf2959_table[][2] = { | 24 | static const u32 rf2959_table[][2] = { |
25 | RF_CHANNEL( 1) = { 0x181979, 0x1e6666 }, | 25 | RF_CHANNEL( 1) = { 0x181979, 0x1e6666 }, |
26 | RF_CHANNEL( 2) = { 0x181989, 0x1e6666 }, | 26 | RF_CHANNEL( 2) = { 0x181989, 0x1e6666 }, |
27 | RF_CHANNEL( 3) = { 0x181999, 0x1e6666 }, | 27 | RF_CHANNEL( 3) = { 0x181999, 0x1e6666 }, |
@@ -228,7 +228,7 @@ static int rf2959_init_hw(struct zd_rf *rf) | |||
228 | static int rf2959_set_channel(struct zd_rf *rf, u8 channel) | 228 | static int rf2959_set_channel(struct zd_rf *rf, u8 channel) |
229 | { | 229 | { |
230 | int i, r; | 230 | int i, r; |
231 | u32 *rv = rf2959_table[channel-1]; | 231 | const u32 *rv = rf2959_table[channel-1]; |
232 | struct zd_chip *chip = zd_rf_to_chip(rf); | 232 | struct zd_chip *chip = zd_rf_to_chip(rf); |
233 | 233 | ||
234 | for (i = 0; i < 2; i++) { | 234 | for (i = 0; i < 2; i++) { |
diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index edaaad2f648b..e04cffc8adf3 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c | |||
@@ -52,6 +52,7 @@ static struct usb_device_id usb_ids[] = { | |||
52 | { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, | 52 | { USB_DEVICE(0x0b3b, 0x1630), .driver_info = DEVICE_ZD1211 }, |
53 | { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, | 53 | { USB_DEVICE(0x0586, 0x3401), .driver_info = DEVICE_ZD1211 }, |
54 | { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, | 54 | { USB_DEVICE(0x14ea, 0xab13), .driver_info = DEVICE_ZD1211 }, |
55 | { USB_DEVICE(0x13b1, 0x001e), .driver_info = DEVICE_ZD1211 }, | ||
55 | /* ZD1211B */ | 56 | /* ZD1211B */ |
56 | { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, | 57 | { USB_DEVICE(0x0ace, 0x1215), .driver_info = DEVICE_ZD1211B }, |
57 | { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, | 58 | { USB_DEVICE(0x157e, 0x300d), .driver_info = DEVICE_ZD1211B }, |
@@ -62,7 +63,10 @@ static struct usb_device_id usb_ids[] = { | |||
62 | { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, | 63 | { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B }, |
63 | { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, | 64 | { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B }, |
64 | { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, | 65 | { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B }, |
66 | { USB_DEVICE(0x0b05, 0x171b), .driver_info = DEVICE_ZD1211B }, | ||
67 | { USB_DEVICE(0x0586, 0x3410), .driver_info = DEVICE_ZD1211B }, | ||
65 | { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B }, | 68 | { USB_DEVICE(0x0baf, 0x0121), .driver_info = DEVICE_ZD1211B }, |
69 | { USB_DEVICE(0x0586, 0x3412), .driver_info = DEVICE_ZD1211B }, | ||
66 | /* "Driverless" devices that need ejecting */ | 70 | /* "Driverless" devices that need ejecting */ |
67 | { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, | 71 | { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER }, |
68 | {} | 72 | {} |
@@ -413,7 +417,7 @@ int zd_usb_enable_int(struct zd_usb *usb) | |||
413 | 417 | ||
414 | dev_dbg_f(zd_usb_dev(usb), "\n"); | 418 | dev_dbg_f(zd_usb_dev(usb), "\n"); |
415 | 419 | ||
416 | urb = usb_alloc_urb(0, GFP_NOFS); | 420 | urb = usb_alloc_urb(0, GFP_KERNEL); |
417 | if (!urb) { | 421 | if (!urb) { |
418 | r = -ENOMEM; | 422 | r = -ENOMEM; |
419 | goto out; | 423 | goto out; |
@@ -431,7 +435,7 @@ int zd_usb_enable_int(struct zd_usb *usb) | |||
431 | 435 | ||
432 | /* TODO: make it a DMA buffer */ | 436 | /* TODO: make it a DMA buffer */ |
433 | r = -ENOMEM; | 437 | r = -ENOMEM; |
434 | transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_NOFS); | 438 | transfer_buffer = kmalloc(USB_MAX_EP_INT_BUFFER, GFP_KERNEL); |
435 | if (!transfer_buffer) { | 439 | if (!transfer_buffer) { |
436 | dev_dbg_f(zd_usb_dev(usb), | 440 | dev_dbg_f(zd_usb_dev(usb), |
437 | "couldn't allocate transfer_buffer\n"); | 441 | "couldn't allocate transfer_buffer\n"); |
@@ -445,7 +449,7 @@ int zd_usb_enable_int(struct zd_usb *usb) | |||
445 | intr->interval); | 449 | intr->interval); |
446 | 450 | ||
447 | dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb); | 451 | dev_dbg_f(zd_usb_dev(usb), "submit urb %p\n", intr->urb); |
448 | r = usb_submit_urb(urb, GFP_NOFS); | 452 | r = usb_submit_urb(urb, GFP_KERNEL); |
449 | if (r) { | 453 | if (r) { |
450 | dev_dbg_f(zd_usb_dev(usb), | 454 | dev_dbg_f(zd_usb_dev(usb), |
451 | "Couldn't submit urb. Error number %d\n", r); | 455 | "Couldn't submit urb. Error number %d\n", r); |
@@ -594,10 +598,10 @@ static struct urb *alloc_urb(struct zd_usb *usb) | |||
594 | struct urb *urb; | 598 | struct urb *urb; |
595 | void *buffer; | 599 | void *buffer; |
596 | 600 | ||
597 | urb = usb_alloc_urb(0, GFP_NOFS); | 601 | urb = usb_alloc_urb(0, GFP_KERNEL); |
598 | if (!urb) | 602 | if (!urb) |
599 | return NULL; | 603 | return NULL; |
600 | buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_NOFS, | 604 | buffer = usb_buffer_alloc(udev, USB_MAX_RX_SIZE, GFP_KERNEL, |
601 | &urb->transfer_dma); | 605 | &urb->transfer_dma); |
602 | if (!buffer) { | 606 | if (!buffer) { |
603 | usb_free_urb(urb); | 607 | usb_free_urb(urb); |
@@ -630,7 +634,7 @@ int zd_usb_enable_rx(struct zd_usb *usb) | |||
630 | dev_dbg_f(zd_usb_dev(usb), "\n"); | 634 | dev_dbg_f(zd_usb_dev(usb), "\n"); |
631 | 635 | ||
632 | r = -ENOMEM; | 636 | r = -ENOMEM; |
633 | urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_NOFS); | 637 | urbs = kcalloc(URBS_COUNT, sizeof(struct urb *), GFP_KERNEL); |
634 | if (!urbs) | 638 | if (!urbs) |
635 | goto error; | 639 | goto error; |
636 | for (i = 0; i < URBS_COUNT; i++) { | 640 | for (i = 0; i < URBS_COUNT; i++) { |
@@ -651,7 +655,7 @@ int zd_usb_enable_rx(struct zd_usb *usb) | |||
651 | spin_unlock_irq(&rx->lock); | 655 | spin_unlock_irq(&rx->lock); |
652 | 656 | ||
653 | for (i = 0; i < URBS_COUNT; i++) { | 657 | for (i = 0; i < URBS_COUNT; i++) { |
654 | r = usb_submit_urb(urbs[i], GFP_NOFS); | 658 | r = usb_submit_urb(urbs[i], GFP_KERNEL); |
655 | if (r) | 659 | if (r) |
656 | goto error_submit; | 660 | goto error_submit; |
657 | } | 661 | } |
@@ -1157,7 +1161,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values, | |||
1157 | } | 1161 | } |
1158 | 1162 | ||
1159 | req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16); | 1163 | req_len = sizeof(struct usb_req_read_regs) + count * sizeof(__le16); |
1160 | req = kmalloc(req_len, GFP_NOFS); | 1164 | req = kmalloc(req_len, GFP_KERNEL); |
1161 | if (!req) | 1165 | if (!req) |
1162 | return -ENOMEM; | 1166 | return -ENOMEM; |
1163 | req->id = cpu_to_le16(USB_REQ_READ_REGS); | 1167 | req->id = cpu_to_le16(USB_REQ_READ_REGS); |
@@ -1220,7 +1224,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs, | |||
1220 | 1224 | ||
1221 | req_len = sizeof(struct usb_req_write_regs) + | 1225 | req_len = sizeof(struct usb_req_write_regs) + |
1222 | count * sizeof(struct reg_data); | 1226 | count * sizeof(struct reg_data); |
1223 | req = kmalloc(req_len, GFP_NOFS); | 1227 | req = kmalloc(req_len, GFP_KERNEL); |
1224 | if (!req) | 1228 | if (!req) |
1225 | return -ENOMEM; | 1229 | return -ENOMEM; |
1226 | 1230 | ||
@@ -1300,7 +1304,7 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits) | |||
1300 | bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); | 1304 | bit_value_template &= ~(RF_IF_LE|RF_CLK|RF_DATA); |
1301 | 1305 | ||
1302 | req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16); | 1306 | req_len = sizeof(struct usb_req_rfwrite) + bits * sizeof(__le16); |
1303 | req = kmalloc(req_len, GFP_NOFS); | 1307 | req = kmalloc(req_len, GFP_KERNEL); |
1304 | if (!req) | 1308 | if (!req) |
1305 | return -ENOMEM; | 1309 | return -ENOMEM; |
1306 | 1310 | ||