diff options
author | Dhananjay Phadke <dhananjay@netxen.com> | 2008-07-21 22:44:01 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-07-22 17:51:12 -0400 |
commit | 623621b07ebc5b72e0bdfa4a50bbb28f4587de0c (patch) | |
tree | a6e472bfa084e79f912ca1b6dcc06dd61332669f /drivers/net/netxen/netxen_nic_hw.c | |
parent | 7830b22cbc5f5e804469b74a3fe0d3a8ed88ca31 (diff) |
netxen: hw multicast filtering
Enable multicast address filtering capabilities in the hardware.
Upto 16 multicast addresses can be programmed for each physical
port. Support "allmulti" mode, if enabled.
Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/netxen/netxen_nic_hw.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_hw.c | 133 |
1 files changed, 124 insertions, 9 deletions
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index fa6d034c242c..93466ec64074 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c | |||
@@ -154,7 +154,6 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) | |||
154 | if (!is_valid_ether_addr(addr->sa_data)) | 154 | if (!is_valid_ether_addr(addr->sa_data)) |
155 | return -EADDRNOTAVAIL; | 155 | return -EADDRNOTAVAIL; |
156 | 156 | ||
157 | DPRINTK(INFO, "valid ether addr\n"); | ||
158 | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | 157 | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); |
159 | 158 | ||
160 | if (adapter->macaddr_set) | 159 | if (adapter->macaddr_set) |
@@ -163,6 +162,91 @@ int netxen_nic_set_mac(struct net_device *netdev, void *p) | |||
163 | return 0; | 162 | return 0; |
164 | } | 163 | } |
165 | 164 | ||
165 | #define NETXEN_UNICAST_ADDR(port, index) \ | ||
166 | (NETXEN_UNICAST_ADDR_BASE+(port*32)+(index*8)) | ||
167 | #define NETXEN_MCAST_ADDR(port, index) \ | ||
168 | (NETXEN_MULTICAST_ADDR_BASE+(port*0x80)+(index*8)) | ||
169 | #define MAC_HI(addr) \ | ||
170 | ((addr[2] << 16) | (addr[1] << 8) | (addr[0])) | ||
171 | #define MAC_LO(addr) \ | ||
172 | ((addr[5] << 16) | (addr[4] << 8) | (addr[3])) | ||
173 | |||
174 | static int | ||
175 | netxen_nic_enable_mcast_filter(struct netxen_adapter *adapter) | ||
176 | { | ||
177 | u32 val = 0; | ||
178 | u16 port = adapter->physical_port; | ||
179 | u8 *addr = adapter->netdev->dev_addr; | ||
180 | |||
181 | if (adapter->mc_enabled) | ||
182 | return 0; | ||
183 | |||
184 | netxen_nic_hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); | ||
185 | val |= (1UL << (28+port)); | ||
186 | netxen_nic_hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); | ||
187 | |||
188 | /* add broadcast addr to filter */ | ||
189 | val = 0xffffff; | ||
190 | netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val); | ||
191 | netxen_crb_writelit_adapter(adapter, | ||
192 | NETXEN_UNICAST_ADDR(port, 0)+4, val); | ||
193 | |||
194 | /* add station addr to filter */ | ||
195 | val = MAC_HI(addr); | ||
196 | netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1), val); | ||
197 | val = MAC_LO(addr); | ||
198 | netxen_crb_writelit_adapter(adapter, | ||
199 | NETXEN_UNICAST_ADDR(port, 1)+4, val); | ||
200 | |||
201 | adapter->mc_enabled = 1; | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int | ||
206 | netxen_nic_disable_mcast_filter(struct netxen_adapter *adapter) | ||
207 | { | ||
208 | u32 val = 0; | ||
209 | u16 port = adapter->physical_port; | ||
210 | u8 *addr = adapter->netdev->dev_addr; | ||
211 | |||
212 | if (!adapter->mc_enabled) | ||
213 | return 0; | ||
214 | |||
215 | netxen_nic_hw_read_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); | ||
216 | val &= ~(1UL << (28+port)); | ||
217 | netxen_nic_hw_write_wx(adapter, NETXEN_MAC_ADDR_CNTL_REG, &val, 4); | ||
218 | |||
219 | val = MAC_HI(addr); | ||
220 | netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 0), val); | ||
221 | val = MAC_LO(addr); | ||
222 | netxen_crb_writelit_adapter(adapter, | ||
223 | NETXEN_UNICAST_ADDR(port, 0)+4, val); | ||
224 | |||
225 | netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1), 0); | ||
226 | netxen_crb_writelit_adapter(adapter, NETXEN_UNICAST_ADDR(port, 1)+4, 0); | ||
227 | |||
228 | adapter->mc_enabled = 0; | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static int | ||
233 | netxen_nic_set_mcast_addr(struct netxen_adapter *adapter, | ||
234 | int index, u8 *addr) | ||
235 | { | ||
236 | u32 hi = 0, lo = 0; | ||
237 | u16 port = adapter->physical_port; | ||
238 | |||
239 | lo = MAC_LO(addr); | ||
240 | hi = MAC_HI(addr); | ||
241 | |||
242 | netxen_crb_writelit_adapter(adapter, | ||
243 | NETXEN_MCAST_ADDR(port, index), hi); | ||
244 | netxen_crb_writelit_adapter(adapter, | ||
245 | NETXEN_MCAST_ADDR(port, index)+4, lo); | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
166 | /* | 250 | /* |
167 | * netxen_nic_set_multi - Multicast | 251 | * netxen_nic_set_multi - Multicast |
168 | */ | 252 | */ |
@@ -170,17 +254,48 @@ void netxen_nic_set_multi(struct net_device *netdev) | |||
170 | { | 254 | { |
171 | struct netxen_adapter *adapter = netdev_priv(netdev); | 255 | struct netxen_adapter *adapter = netdev_priv(netdev); |
172 | struct dev_mc_list *mc_ptr; | 256 | struct dev_mc_list *mc_ptr; |
257 | u8 null_addr[6]; | ||
258 | int index = 0; | ||
259 | |||
260 | memset(null_addr, 0, 6); | ||
173 | 261 | ||
174 | mc_ptr = netdev->mc_list; | ||
175 | if (netdev->flags & IFF_PROMISC) { | 262 | if (netdev->flags & IFF_PROMISC) { |
176 | if (adapter->set_promisc) | 263 | |
177 | adapter->set_promisc(adapter, | 264 | adapter->set_promisc(adapter, |
178 | NETXEN_NIU_PROMISC_MODE); | 265 | NETXEN_NIU_PROMISC_MODE); |
179 | } else { | 266 | |
180 | if (adapter->unset_promisc) | 267 | /* Full promiscuous mode */ |
181 | adapter->unset_promisc(adapter, | 268 | netxen_nic_disable_mcast_filter(adapter); |
182 | NETXEN_NIU_NON_PROMISC_MODE); | 269 | |
270 | return; | ||
271 | } | ||
272 | |||
273 | if (netdev->mc_count == 0) { | ||
274 | adapter->set_promisc(adapter, | ||
275 | NETXEN_NIU_NON_PROMISC_MODE); | ||
276 | netxen_nic_disable_mcast_filter(adapter); | ||
277 | return; | ||
278 | } | ||
279 | |||
280 | adapter->set_promisc(adapter, NETXEN_NIU_ALLMULTI_MODE); | ||
281 | if (netdev->flags & IFF_ALLMULTI || | ||
282 | netdev->mc_count > adapter->max_mc_count) { | ||
283 | netxen_nic_disable_mcast_filter(adapter); | ||
284 | return; | ||
183 | } | 285 | } |
286 | |||
287 | netxen_nic_enable_mcast_filter(adapter); | ||
288 | |||
289 | for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next, index++) | ||
290 | netxen_nic_set_mcast_addr(adapter, index, mc_ptr->dmi_addr); | ||
291 | |||
292 | if (index != netdev->mc_count) | ||
293 | printk(KERN_WARNING "%s: %s multicast address count mismatch\n", | ||
294 | netxen_nic_driver_name, netdev->name); | ||
295 | |||
296 | /* Clear out remaining addresses */ | ||
297 | for (; index < adapter->max_mc_count; index++) | ||
298 | netxen_nic_set_mcast_addr(adapter, index, null_addr); | ||
184 | } | 299 | } |
185 | 300 | ||
186 | /* | 301 | /* |