diff options
author | Amit S. Kale <amitkale@netxen.com> | 2006-10-21 15:33:03 -0400 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-02 00:11:58 -0500 |
commit | 3d396eb17e9f8c5f59314078b45b88647591378d (patch) | |
tree | d0c54e4555c1bee13d403f6dad36b40ae26d74a2 /drivers/net/netxen/netxen_nic_hw.c | |
parent | f3d1fca3eb05cf6ff3879a385a15d24fbf556c57 (diff) |
Add NetXen 1G/10G ethernet driver.
Signed-off-by: Amit S. Kale <amitkale@netxen.com>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/netxen/netxen_nic_hw.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_hw.c | 936 |
1 files changed, 936 insertions, 0 deletions
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c new file mode 100644 index 000000000000..c7d97054d05c --- /dev/null +++ b/drivers/net/netxen/netxen_nic_hw.c | |||
@@ -0,0 +1,936 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2003 - 2006 NetXen, Inc. | ||
3 | * All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
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 | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, | ||
18 | * MA 02111-1307, USA. | ||
19 | * | ||
20 | * The full GNU General Public License is included in this distribution | ||
21 | * in the file called LICENSE. | ||
22 | * | ||
23 | * Contact Information: | ||
24 | * info@netxen.com | ||
25 | * NetXen, | ||
26 | * 3965 Freedom Circle, Fourth floor, | ||
27 | * Santa Clara, CA 95054 | ||
28 | * | ||
29 | * | ||
30 | * Source file for NIC routines to access the Phantom hardware | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #include "netxen_nic.h" | ||
35 | #include "netxen_nic_hw.h" | ||
36 | #include "netxen_nic_phan_reg.h" | ||
37 | |||
38 | /* PCI Windowing for DDR regions. */ | ||
39 | |||
40 | #define ADDR_IN_RANGE(addr, low, high) \ | ||
41 | (((addr) <= (high)) && ((addr) >= (low))) | ||
42 | |||
43 | #define NETXEN_FLASH_BASE (BOOTLD_START) | ||
44 | #define NETXEN_PHANTOM_MEM_BASE (NETXEN_FLASH_BASE) | ||
45 | #define NETXEN_MAX_MTU 8000 | ||
46 | #define NETXEN_MIN_MTU 64 | ||
47 | #define NETXEN_ETH_FCS_SIZE 4 | ||
48 | #define NETXEN_ENET_HEADER_SIZE 14 | ||
49 | #define NETXEN_WINDOW_ONE 0x2000000 /* CRB Window: bit 25 of CRB address */ | ||
50 | #define NETXEN_FIRMWARE_LEN ((16 * 1024) / 4) | ||
51 | #define NETXEN_NIU_HDRSIZE (0x1 << 6) | ||
52 | #define NETXEN_NIU_TLRSIZE (0x1 << 5) | ||
53 | |||
54 | unsigned long netxen_nic_pci_set_window(void __iomem * pci_base, | ||
55 | unsigned long long addr); | ||
56 | void netxen_free_hw_resources(struct netxen_adapter *adapter); | ||
57 | |||
58 | int netxen_nic_set_mac(struct net_device *netdev, void *p) | ||
59 | { | ||
60 | struct netxen_port *port = netdev_priv(netdev); | ||
61 | struct netxen_adapter *adapter = port->adapter; | ||
62 | struct sockaddr *addr = p; | ||
63 | |||
64 | if (netif_running(netdev)) | ||
65 | return -EBUSY; | ||
66 | |||
67 | if (!is_valid_ether_addr(addr->sa_data)) | ||
68 | return -EADDRNOTAVAIL; | ||
69 | |||
70 | DPRINTK(INFO, "valid ether addr\n"); | ||
71 | memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len); | ||
72 | |||
73 | if (adapter->ops->macaddr_set) | ||
74 | adapter->ops->macaddr_set(port, addr->sa_data); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | /* | ||
80 | * netxen_nic_set_multi - Multicast | ||
81 | */ | ||
82 | void netxen_nic_set_multi(struct net_device *netdev) | ||
83 | { | ||
84 | struct netxen_port *port = netdev_priv(netdev); | ||
85 | struct netxen_adapter *adapter = port->adapter; | ||
86 | struct dev_mc_list *mc_ptr; | ||
87 | __le32 netxen_mac_addr_cntl_data = 0; | ||
88 | |||
89 | mc_ptr = netdev->mc_list; | ||
90 | if (netdev->flags & IFF_PROMISC) { | ||
91 | if (adapter->ops->set_promisc) | ||
92 | adapter->ops->set_promisc(adapter, | ||
93 | port->portnum, | ||
94 | NETXEN_NIU_PROMISC_MODE); | ||
95 | } else { | ||
96 | if (adapter->ops->unset_promisc) | ||
97 | adapter->ops->unset_promisc(adapter, | ||
98 | port->portnum, | ||
99 | NETXEN_NIU_NON_PROMISC_MODE); | ||
100 | } | ||
101 | if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { | ||
102 | netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x03); | ||
103 | netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00); | ||
104 | netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x00); | ||
105 | netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x00); | ||
106 | netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x00); | ||
107 | netxen_nic_mcr_set_enable_xtnd0(netxen_mac_addr_cntl_data); | ||
108 | netxen_nic_mcr_set_enable_xtnd1(netxen_mac_addr_cntl_data); | ||
109 | netxen_nic_mcr_set_enable_xtnd2(netxen_mac_addr_cntl_data); | ||
110 | netxen_nic_mcr_set_enable_xtnd3(netxen_mac_addr_cntl_data); | ||
111 | } else { | ||
112 | netxen_nic_mcr_set_mode_select(netxen_mac_addr_cntl_data, 0x00); | ||
113 | netxen_nic_mcr_set_id_pool0(netxen_mac_addr_cntl_data, 0x00); | ||
114 | netxen_nic_mcr_set_id_pool1(netxen_mac_addr_cntl_data, 0x01); | ||
115 | netxen_nic_mcr_set_id_pool2(netxen_mac_addr_cntl_data, 0x02); | ||
116 | netxen_nic_mcr_set_id_pool3(netxen_mac_addr_cntl_data, 0x03); | ||
117 | } | ||
118 | writel(netxen_mac_addr_cntl_data, | ||
119 | NETXEN_CRB_NORMALIZE(adapter, NETXEN_MAC_ADDR_CNTL_REG)); | ||
120 | if (adapter->ahw.board_type == NETXEN_NIC_XGBE) { | ||
121 | writel(netxen_mac_addr_cntl_data, | ||
122 | NETXEN_CRB_NORMALIZE(adapter, | ||
123 | NETXEN_MULTICAST_ADDR_HI_0)); | ||
124 | } else { | ||
125 | writel(netxen_mac_addr_cntl_data, | ||
126 | NETXEN_CRB_NORMALIZE(adapter, | ||
127 | NETXEN_MULTICAST_ADDR_HI_1)); | ||
128 | } | ||
129 | netxen_mac_addr_cntl_data = 0; | ||
130 | writel(netxen_mac_addr_cntl_data, | ||
131 | NETXEN_CRB_NORMALIZE(adapter, NETXEN_NIU_GB_DROP_WRONGADDR)); | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * netxen_nic_change_mtu - Change the Maximum Transfer Unit | ||
136 | * @returns 0 on success, negative on failure | ||
137 | */ | ||
138 | int netxen_nic_change_mtu(struct net_device *netdev, int mtu) | ||
139 | { | ||
140 | struct netxen_port *port = netdev_priv(netdev); | ||
141 | struct netxen_adapter *adapter = port->adapter; | ||
142 | int eff_mtu = mtu + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE; | ||
143 | |||
144 | if ((eff_mtu > NETXEN_MAX_MTU) || (eff_mtu < NETXEN_MIN_MTU)) { | ||
145 | printk(KERN_ERR "%s: %s %d is not supported.\n", | ||
146 | netxen_nic_driver_name, netdev->name, mtu); | ||
147 | return -EINVAL; | ||
148 | } | ||
149 | |||
150 | if (adapter->ops->set_mtu) | ||
151 | adapter->ops->set_mtu(port, mtu); | ||
152 | netdev->mtu = mtu; | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | /* | ||
158 | * check if the firmware has been downloaded and ready to run and | ||
159 | * setup the address for the descriptors in the adapter | ||
160 | */ | ||
161 | int netxen_nic_hw_resources(struct netxen_adapter *adapter) | ||
162 | { | ||
163 | struct netxen_hardware_context *hw = &adapter->ahw; | ||
164 | int i; | ||
165 | u32 state = 0; | ||
166 | void *addr; | ||
167 | int loops = 0, err = 0; | ||
168 | int ctx, ring; | ||
169 | u32 card_cmdring = 0; | ||
170 | struct netxen_rcv_desc_crb *rcv_desc_crb = NULL; | ||
171 | struct netxen_recv_context *recv_ctx; | ||
172 | struct netxen_rcv_desc_ctx *rcv_desc; | ||
173 | struct cmd_desc_type0 *pcmd; | ||
174 | |||
175 | DPRINTK(INFO, "pci_base: %lx\n", adapter->ahw.pci_base); | ||
176 | DPRINTK(INFO, "crb_base: %lx %lx", NETXEN_PCI_CRBSPACE, | ||
177 | adapter->ahw.pci_base + NETXEN_PCI_CRBSPACE); | ||
178 | DPRINTK(INFO, "cam base: %lx %lx", NETXEN_CRB_CAM, | ||
179 | adapter->ahw.pci_base + NETXEN_CRB_CAM); | ||
180 | DPRINTK(INFO, "cam RAM: %lx %lx", NETXEN_CAM_RAM_BASE, | ||
181 | adapter->ahw.pci_base + NETXEN_CAM_RAM_BASE); | ||
182 | DPRINTK(INFO, "NIC base:%lx %lx\n", NIC_CRB_BASE_PORT1, | ||
183 | adapter->ahw.pci_base + NIC_CRB_BASE_PORT1); | ||
184 | |||
185 | /* Window 1 call */ | ||
186 | card_cmdring = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_CMDRING)); | ||
187 | |||
188 | DPRINTK(INFO, "Command Peg sends 0x%x for cmdring base\n", | ||
189 | card_cmdring); | ||
190 | |||
191 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | ||
192 | DPRINTK(INFO, "Command Peg ready..waiting for rcv peg\n"); | ||
193 | loops = 0; | ||
194 | state = 0; | ||
195 | /* Window 1 call */ | ||
196 | state = readl(NETXEN_CRB_NORMALIZE(adapter, | ||
197 | recv_crb_registers[ctx]. | ||
198 | crb_rcvpeg_state)); | ||
199 | while (state != PHAN_PEG_RCV_INITIALIZED && loops < 20) { | ||
200 | udelay(100); | ||
201 | /* Window 1 call */ | ||
202 | state = readl(NETXEN_CRB_NORMALIZE(adapter, | ||
203 | recv_crb_registers | ||
204 | [ctx]. | ||
205 | crb_rcvpeg_state)); | ||
206 | loops++; | ||
207 | } | ||
208 | if (loops >= 20) { | ||
209 | printk(KERN_ERR "Rcv Peg initialization not complete:" | ||
210 | "%x.\n", state); | ||
211 | err = -EIO; | ||
212 | return err; | ||
213 | } | ||
214 | } | ||
215 | DPRINTK(INFO, "Recieve Peg ready too. starting stuff\n"); | ||
216 | |||
217 | addr = pci_alloc_consistent(adapter->ahw.pdev, | ||
218 | sizeof(struct cmd_desc_type0) * | ||
219 | adapter->max_tx_desc_count, | ||
220 | &hw->cmd_desc_phys_addr); | ||
221 | if (addr == NULL) { | ||
222 | DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); | ||
223 | err = -ENOMEM; | ||
224 | return err; | ||
225 | } | ||
226 | |||
227 | /* we need to prelink all of the cmd descriptors */ | ||
228 | pcmd = (struct cmd_desc_type0 *)addr; | ||
229 | for (i = 1; i < adapter->max_tx_desc_count; i++) { | ||
230 | pcmd->netxen_next = | ||
231 | (card_cmdring + i * sizeof(struct cmd_desc_type0)); | ||
232 | pcmd++; | ||
233 | } | ||
234 | /* fill in last link (point to first) */ | ||
235 | pcmd->netxen_next = card_cmdring; | ||
236 | |||
237 | hw->cmd_desc_head = (struct cmd_desc_type0 *)addr; | ||
238 | |||
239 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | ||
240 | recv_ctx = &adapter->recv_ctx[ctx]; | ||
241 | |||
242 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { | ||
243 | rcv_desc = &recv_ctx->rcv_desc[ring]; | ||
244 | addr = pci_alloc_consistent(adapter->ahw.pdev, | ||
245 | RCV_DESC_RINGSIZE, | ||
246 | &rcv_desc->phys_addr); | ||
247 | if (addr == NULL) { | ||
248 | DPRINTK(ERR, "bad return from " | ||
249 | "pci_alloc_consistent\n"); | ||
250 | netxen_free_hw_resources(adapter); | ||
251 | err = -ENOMEM; | ||
252 | return err; | ||
253 | } | ||
254 | rcv_desc->desc_head = (struct rcv_desc *)addr; | ||
255 | } | ||
256 | |||
257 | addr = pci_alloc_consistent(adapter->ahw.pdev, | ||
258 | STATUS_DESC_RINGSIZE, | ||
259 | &recv_ctx-> | ||
260 | rcv_status_desc_phys_addr); | ||
261 | if (addr == NULL) { | ||
262 | DPRINTK(ERR, "bad return from" | ||
263 | " pci_alloc_consistent\n"); | ||
264 | netxen_free_hw_resources(adapter); | ||
265 | err = -ENOMEM; | ||
266 | return err; | ||
267 | } | ||
268 | recv_ctx->rcv_status_desc_head = (struct status_desc *)addr; | ||
269 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { | ||
270 | rcv_desc = &recv_ctx->rcv_desc[ring]; | ||
271 | rcv_desc_crb = | ||
272 | &recv_crb_registers[ctx].rcv_desc_crb[ring]; | ||
273 | DPRINTK(INFO, "ring #%d crb global ring reg 0x%x\n", | ||
274 | ring, rcv_desc_crb->crb_globalrcv_ring); | ||
275 | /* Window = 1 */ | ||
276 | writel(rcv_desc->phys_addr, | ||
277 | NETXEN_CRB_NORMALIZE(adapter, | ||
278 | rcv_desc_crb-> | ||
279 | crb_globalrcv_ring)); | ||
280 | DPRINTK(INFO, "GLOBAL_RCV_RING ctx %d, addr 0x%x" | ||
281 | " val 0x%x," | ||
282 | " virt %p\n", ctx, | ||
283 | rcv_desc_crb->crb_globalrcv_ring, | ||
284 | rcv_desc->phys_addr, rcv_desc->desc_head); | ||
285 | } | ||
286 | |||
287 | /* Window = 1 */ | ||
288 | writel(recv_ctx->rcv_status_desc_phys_addr, | ||
289 | NETXEN_CRB_NORMALIZE(adapter, | ||
290 | recv_crb_registers[ctx]. | ||
291 | crb_rcvstatus_ring)); | ||
292 | DPRINTK(INFO, "RCVSTATUS_RING, ctx %d, addr 0x%x," | ||
293 | " val 0x%x,virt%p\n", | ||
294 | ctx, | ||
295 | recv_crb_registers[ctx].crb_rcvstatus_ring, | ||
296 | recv_ctx->rcv_status_desc_phys_addr, | ||
297 | recv_ctx->rcv_status_desc_head); | ||
298 | } | ||
299 | /* Window = 1 */ | ||
300 | writel(hw->cmd_desc_phys_addr, | ||
301 | NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO)); | ||
302 | |||
303 | return err; | ||
304 | } | ||
305 | |||
306 | void netxen_free_hw_resources(struct netxen_adapter *adapter) | ||
307 | { | ||
308 | struct netxen_recv_context *recv_ctx; | ||
309 | struct netxen_rcv_desc_ctx *rcv_desc; | ||
310 | int ctx, ring; | ||
311 | |||
312 | if (adapter->ahw.cmd_desc_head != NULL) { | ||
313 | pci_free_consistent(adapter->ahw.pdev, | ||
314 | sizeof(struct cmd_desc_type0) * | ||
315 | adapter->max_tx_desc_count, | ||
316 | adapter->ahw.cmd_desc_head, | ||
317 | adapter->ahw.cmd_desc_phys_addr); | ||
318 | adapter->ahw.cmd_desc_head = NULL; | ||
319 | } | ||
320 | |||
321 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | ||
322 | recv_ctx = &adapter->recv_ctx[ctx]; | ||
323 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { | ||
324 | rcv_desc = &recv_ctx->rcv_desc[ring]; | ||
325 | |||
326 | if (rcv_desc->desc_head != NULL) { | ||
327 | pci_free_consistent(adapter->ahw.pdev, | ||
328 | RCV_DESC_RINGSIZE, | ||
329 | rcv_desc->desc_head, | ||
330 | rcv_desc->phys_addr); | ||
331 | rcv_desc->desc_head = NULL; | ||
332 | } | ||
333 | } | ||
334 | |||
335 | if (recv_ctx->rcv_status_desc_head != NULL) { | ||
336 | pci_free_consistent(adapter->ahw.pdev, | ||
337 | STATUS_DESC_RINGSIZE, | ||
338 | recv_ctx->rcv_status_desc_head, | ||
339 | recv_ctx-> | ||
340 | rcv_status_desc_phys_addr); | ||
341 | recv_ctx->rcv_status_desc_head = NULL; | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | |||
346 | void netxen_tso_check(struct netxen_adapter *adapter, | ||
347 | struct cmd_desc_type0 *desc, struct sk_buff *skb) | ||
348 | { | ||
349 | if (desc->mss) { | ||
350 | desc->total_hdr_length = sizeof(struct ethhdr) + | ||
351 | ((skb->nh.iph)->ihl * sizeof(u32)) + | ||
352 | ((skb->h.th)->doff * sizeof(u32)); | ||
353 | desc->opcode = TX_TCP_LSO; | ||
354 | } else if (skb->ip_summed == CHECKSUM_HW) { | ||
355 | if (skb->nh.iph->protocol == IPPROTO_TCP) { | ||
356 | desc->opcode = TX_TCP_PKT; | ||
357 | } else if (skb->nh.iph->protocol == IPPROTO_UDP) { | ||
358 | desc->opcode = TX_UDP_PKT; | ||
359 | } else { | ||
360 | return; | ||
361 | } | ||
362 | } | ||
363 | CMD_DESC_TCP_HDR_OFFSET_WRT(desc, skb->h.raw - skb->data); | ||
364 | desc->length_tcp_hdr = cpu_to_le32(desc->length_tcp_hdr); | ||
365 | desc->ip_hdr_offset = skb->nh.raw - skb->data; | ||
366 | adapter->stats.xmitcsummed++; | ||
367 | } | ||
368 | |||
369 | int netxen_is_flash_supported(struct netxen_adapter *adapter) | ||
370 | { | ||
371 | const int locs[] = { 0, 0x4, 0x100, 0x4000, 0x4128 }; | ||
372 | int addr, val01, val02, i, j; | ||
373 | |||
374 | /* if the flash size less than 4Mb, make huge war cry and die */ | ||
375 | for (j = 1; j < 4; j++) { | ||
376 | addr = j * 0x100000; | ||
377 | for (i = 0; i < (sizeof(locs) / sizeof(locs[0])); i++) { | ||
378 | if (netxen_rom_fast_read(adapter, locs[i], &val01) == 0 | ||
379 | && netxen_rom_fast_read(adapter, (addr + locs[i]), | ||
380 | &val02) == 0) { | ||
381 | if (val01 == val02) | ||
382 | return -1; | ||
383 | } else | ||
384 | return -1; | ||
385 | } | ||
386 | } | ||
387 | |||
388 | return 0; | ||
389 | } | ||
390 | |||
391 | static int netxen_get_flash_block(struct netxen_adapter *adapter, int base, | ||
392 | int size, u32 * buf) | ||
393 | { | ||
394 | int i, addr; | ||
395 | u32 *ptr32; | ||
396 | |||
397 | addr = base; | ||
398 | ptr32 = buf; | ||
399 | for (i = 0; i < size / sizeof(u32); i++) { | ||
400 | if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) | ||
401 | return -1; | ||
402 | ptr32++; | ||
403 | addr += sizeof(u32); | ||
404 | } | ||
405 | if ((char *)buf + size > (char *)ptr32) { | ||
406 | u32 local; | ||
407 | |||
408 | if (netxen_rom_fast_read(adapter, addr, &local) == -1) | ||
409 | return -1; | ||
410 | memcpy(ptr32, &local, (char *)buf + size - (char *)ptr32); | ||
411 | } | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, u64 mac[]) | ||
417 | { | ||
418 | u32 *pmac = (u32 *) & mac[0]; | ||
419 | |||
420 | if (netxen_get_flash_block(adapter, | ||
421 | USER_START + | ||
422 | offsetof(struct netxen_new_user_info, | ||
423 | mac_addr), | ||
424 | FLASH_NUM_PORTS * sizeof(u64), pmac) == -1) { | ||
425 | return -1; | ||
426 | } | ||
427 | if (*mac == ~0ULL) { | ||
428 | if (netxen_get_flash_block(adapter, | ||
429 | USER_START_OLD + | ||
430 | offsetof(struct netxen_user_old_info, | ||
431 | mac_addr), | ||
432 | FLASH_NUM_PORTS * sizeof(u64), | ||
433 | pmac) == -1) | ||
434 | return -1; | ||
435 | if (*mac == ~0ULL) | ||
436 | return -1; | ||
437 | } | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * Changes the CRB window to the specified window. | ||
443 | */ | ||
444 | void netxen_nic_pci_change_crbwindow(struct netxen_adapter *adapter, u32 wndw) | ||
445 | { | ||
446 | void __iomem *offset; | ||
447 | u32 tmp; | ||
448 | int count = 0; | ||
449 | |||
450 | if (adapter->curr_window == wndw) | ||
451 | return; | ||
452 | |||
453 | /* | ||
454 | * Move the CRB window. | ||
455 | * We need to write to the "direct access" region of PCI | ||
456 | * to avoid a race condition where the window register has | ||
457 | * not been successfully written across CRB before the target | ||
458 | * register address is received by PCI. The direct region bypasses | ||
459 | * the CRB bus. | ||
460 | */ | ||
461 | offset = adapter->ahw.pci_base + NETXEN_PCIX_PH_REG(PCIX_CRB_WINDOW); | ||
462 | |||
463 | if (wndw & 0x1) | ||
464 | wndw = NETXEN_WINDOW_ONE; | ||
465 | |||
466 | writel(wndw, offset); | ||
467 | |||
468 | /* MUST make sure window is set before we forge on... */ | ||
469 | while ((tmp = readl(offset)) != wndw) { | ||
470 | printk(KERN_WARNING "%s: %s WARNING: CRB window value not " | ||
471 | "registered properly: 0x%08x.\n", | ||
472 | netxen_nic_driver_name, __FUNCTION__, tmp); | ||
473 | mdelay(1); | ||
474 | if (count >= 10) | ||
475 | break; | ||
476 | count++; | ||
477 | } | ||
478 | |||
479 | adapter->curr_window = wndw; | ||
480 | } | ||
481 | |||
482 | void netxen_load_firmware(struct netxen_adapter *adapter) | ||
483 | { | ||
484 | int i; | ||
485 | long data, size = 0; | ||
486 | long flashaddr = NETXEN_FLASH_BASE, memaddr = NETXEN_PHANTOM_MEM_BASE; | ||
487 | u64 off; | ||
488 | void __iomem *addr; | ||
489 | |||
490 | size = NETXEN_FIRMWARE_LEN; | ||
491 | writel(1, NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_CAS_RST)); | ||
492 | |||
493 | for (i = 0; i < size; i++) { | ||
494 | if (netxen_rom_fast_read(adapter, flashaddr, (int *)&data) != 0) { | ||
495 | DPRINTK(ERR, | ||
496 | "Error in netxen_rom_fast_read(). Will skip" | ||
497 | "loading flash image\n"); | ||
498 | return; | ||
499 | } | ||
500 | off = netxen_nic_pci_set_window(adapter->ahw.pci_base, memaddr); | ||
501 | addr = (adapter->ahw.pci_base + off); | ||
502 | writel(data, addr); | ||
503 | flashaddr += 4; | ||
504 | memaddr += 4; | ||
505 | } | ||
506 | udelay(100); | ||
507 | /* make sure Casper is powered on */ | ||
508 | writel(0x3fff, | ||
509 | NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL)); | ||
510 | writel(0, NETXEN_CRB_NORMALIZE(adapter, NETXEN_ROMUSB_GLB_CAS_RST)); | ||
511 | |||
512 | udelay(100); | ||
513 | } | ||
514 | |||
515 | int | ||
516 | netxen_nic_hw_write_wx(struct netxen_adapter *adapter, u64 off, void *data, | ||
517 | int len) | ||
518 | { | ||
519 | void __iomem *addr; | ||
520 | |||
521 | if (ADDR_IN_WINDOW1(off)) { | ||
522 | addr = NETXEN_CRB_NORMALIZE(adapter, off); | ||
523 | } else { /* Window 0 */ | ||
524 | addr = adapter->ahw.pci_base + off; | ||
525 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
526 | } | ||
527 | |||
528 | DPRINTK(INFO, "writing to base %lx offset %llx addr %p" | ||
529 | " data %llx len %d\n", | ||
530 | adapter->ahw.pci_base, off, addr, | ||
531 | *(unsigned long long *)data, len); | ||
532 | switch (len) { | ||
533 | case 1: | ||
534 | writeb(*(u8 *) data, addr); | ||
535 | break; | ||
536 | case 2: | ||
537 | writew(*(u16 *) data, addr); | ||
538 | break; | ||
539 | case 4: | ||
540 | writel(*(u32 *) data, addr); | ||
541 | break; | ||
542 | case 8: | ||
543 | writeq(*(u64 *) data, addr); | ||
544 | break; | ||
545 | default: | ||
546 | DPRINTK(INFO, | ||
547 | "writing data %lx to offset %llx, num words=%d\n", | ||
548 | *(unsigned long *)data, off, (len >> 3)); | ||
549 | |||
550 | netxen_nic_hw_block_write64((u64 __iomem *) data, addr, | ||
551 | (len >> 3)); | ||
552 | break; | ||
553 | } | ||
554 | if (!ADDR_IN_WINDOW1(off)) | ||
555 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
556 | |||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | int | ||
561 | netxen_nic_hw_read_wx(struct netxen_adapter *adapter, u64 off, void *data, | ||
562 | int len) | ||
563 | { | ||
564 | void __iomem *addr; | ||
565 | |||
566 | if (ADDR_IN_WINDOW1(off)) { /* Window 1 */ | ||
567 | addr = NETXEN_CRB_NORMALIZE(adapter, off); | ||
568 | } else { /* Window 0 */ | ||
569 | addr = adapter->ahw.pci_base + off; | ||
570 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
571 | } | ||
572 | |||
573 | DPRINTK(INFO, "reading from base %lx offset %llx addr %p\n", | ||
574 | adapter->ahw.pci_base, off, addr); | ||
575 | switch (len) { | ||
576 | case 1: | ||
577 | *(u8 *) data = readb(addr); | ||
578 | break; | ||
579 | case 2: | ||
580 | *(u16 *) data = readw(addr); | ||
581 | break; | ||
582 | case 4: | ||
583 | *(u32 *) data = readl(addr); | ||
584 | break; | ||
585 | case 8: | ||
586 | *(u64 *) data = readq(addr); | ||
587 | break; | ||
588 | default: | ||
589 | netxen_nic_hw_block_read64((u64 __iomem *) data, addr, | ||
590 | (len >> 3)); | ||
591 | break; | ||
592 | } | ||
593 | DPRINTK(INFO, "read %lx\n", *(unsigned long *)data); | ||
594 | |||
595 | if (!ADDR_IN_WINDOW1(off)) | ||
596 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
597 | |||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | void netxen_nic_reg_write(struct netxen_adapter *adapter, u64 off, u32 val) | ||
602 | { /* Only for window 1 */ | ||
603 | void __iomem *addr; | ||
604 | |||
605 | addr = NETXEN_CRB_NORMALIZE(adapter, off); | ||
606 | DPRINTK(INFO, "writing to base %lx offset %llx addr %p data %x\n", | ||
607 | adapter->ahw.pci_base, off, addr, val); | ||
608 | writel(val, addr); | ||
609 | |||
610 | } | ||
611 | |||
612 | int netxen_nic_reg_read(struct netxen_adapter *adapter, u64 off) | ||
613 | { /* Only for window 1 */ | ||
614 | void __iomem *addr; | ||
615 | int val; | ||
616 | |||
617 | addr = NETXEN_CRB_NORMALIZE(adapter, off); | ||
618 | DPRINTK(INFO, "reading from base %lx offset %llx addr %p\n", | ||
619 | adapter->ahw.pci_base, off, addr); | ||
620 | val = readl(addr); | ||
621 | writel(val, addr); | ||
622 | |||
623 | return val; | ||
624 | } | ||
625 | |||
626 | /* Change the window to 0, write and change back to window 1. */ | ||
627 | void netxen_nic_write_w0(struct netxen_adapter *adapter, u32 index, u32 value) | ||
628 | { | ||
629 | void __iomem *addr; | ||
630 | |||
631 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
632 | addr = (void __iomem *)(adapter->ahw.pci_base + index); | ||
633 | writel(value, addr); | ||
634 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
635 | } | ||
636 | |||
637 | /* Change the window to 0, read and change back to window 1. */ | ||
638 | void netxen_nic_read_w0(struct netxen_adapter *adapter, u32 index, u32 * value) | ||
639 | { | ||
640 | void __iomem *addr; | ||
641 | |||
642 | addr = (void __iomem *)(adapter->ahw.pci_base + index); | ||
643 | |||
644 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
645 | *value = readl(addr); | ||
646 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
647 | } | ||
648 | |||
649 | int netxen_pci_set_window_warning_count = 0; | ||
650 | |||
651 | unsigned long | ||
652 | netxen_nic_pci_set_window(void __iomem * pci_base, unsigned long long addr) | ||
653 | { | ||
654 | static int ddr_mn_window = -1; | ||
655 | static int qdr_sn_window = -1; | ||
656 | int window; | ||
657 | |||
658 | if (ADDR_IN_RANGE(addr, NETXEN_ADDR_DDR_NET, NETXEN_ADDR_DDR_NET_MAX)) { | ||
659 | /* DDR network side */ | ||
660 | addr -= NETXEN_ADDR_DDR_NET; | ||
661 | window = (addr >> 25) & 0x3ff; | ||
662 | if (ddr_mn_window != window) { | ||
663 | ddr_mn_window = window; | ||
664 | writel(window, pci_base + | ||
665 | NETXEN_PCIX_PH_REG(PCIX_MN_WINDOW)); | ||
666 | /* MUST make sure window is set before we forge on... */ | ||
667 | readl(pci_base + NETXEN_PCIX_PH_REG(PCIX_MN_WINDOW)); | ||
668 | } | ||
669 | addr -= (window * 0x2000000); | ||
670 | addr += NETXEN_PCI_DDR_NET; | ||
671 | } else if (ADDR_IN_RANGE(addr, NETXEN_ADDR_OCM0, NETXEN_ADDR_OCM0_MAX)) { | ||
672 | addr -= NETXEN_ADDR_OCM0; | ||
673 | addr += NETXEN_PCI_OCM0; | ||
674 | } else if (ADDR_IN_RANGE(addr, NETXEN_ADDR_OCM1, NETXEN_ADDR_OCM1_MAX)) { | ||
675 | addr -= NETXEN_ADDR_OCM1; | ||
676 | addr += NETXEN_PCI_OCM1; | ||
677 | } else | ||
678 | if (ADDR_IN_RANGE | ||
679 | (addr, NETXEN_ADDR_QDR_NET, NETXEN_ADDR_QDR_NET_MAX)) { | ||
680 | /* QDR network side */ | ||
681 | addr -= NETXEN_ADDR_QDR_NET; | ||
682 | window = (addr >> 22) & 0x3f; | ||
683 | if (qdr_sn_window != window) { | ||
684 | qdr_sn_window = window; | ||
685 | writel((window << 22), pci_base + | ||
686 | NETXEN_PCIX_PH_REG(PCIX_SN_WINDOW)); | ||
687 | /* MUST make sure window is set before we forge on... */ | ||
688 | readl(pci_base + NETXEN_PCIX_PH_REG(PCIX_SN_WINDOW)); | ||
689 | } | ||
690 | addr -= (window * 0x400000); | ||
691 | addr += NETXEN_PCI_QDR_NET; | ||
692 | } else { | ||
693 | /* | ||
694 | * peg gdb frequently accesses memory that doesn't exist, | ||
695 | * this limits the chit chat so debugging isn't slowed down. | ||
696 | */ | ||
697 | if ((netxen_pci_set_window_warning_count++ < 8) | ||
698 | || (netxen_pci_set_window_warning_count % 64 == 0)) | ||
699 | printk("%s: Warning:netxen_nic_pci_set_window()" | ||
700 | " Unknown address range!\n", | ||
701 | netxen_nic_driver_name); | ||
702 | |||
703 | } | ||
704 | return addr; | ||
705 | } | ||
706 | |||
707 | int netxen_nic_get_board_info(struct netxen_adapter *adapter) | ||
708 | { | ||
709 | int rv = 0; | ||
710 | int addr = BRDCFG_START; | ||
711 | struct netxen_board_info *boardinfo; | ||
712 | int index; | ||
713 | u32 *ptr32; | ||
714 | |||
715 | boardinfo = &adapter->ahw.boardcfg; | ||
716 | ptr32 = (u32 *) boardinfo; | ||
717 | |||
718 | for (index = 0; index < sizeof(struct netxen_board_info) / sizeof(u32); | ||
719 | index++) { | ||
720 | if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) { | ||
721 | return -EIO; | ||
722 | } | ||
723 | ptr32++; | ||
724 | addr += sizeof(u32); | ||
725 | } | ||
726 | if (boardinfo->magic != NETXEN_BDINFO_MAGIC) { | ||
727 | printk("%s: ERROR reading %s board config." | ||
728 | " Read %x, expected %x\n", netxen_nic_driver_name, | ||
729 | netxen_nic_driver_name, | ||
730 | boardinfo->magic, NETXEN_BDINFO_MAGIC); | ||
731 | rv = -1; | ||
732 | } | ||
733 | if (boardinfo->header_version != NETXEN_BDINFO_VERSION) { | ||
734 | printk("%s: Unknown board config version." | ||
735 | " Read %x, expected %x\n", netxen_nic_driver_name, | ||
736 | boardinfo->header_version, NETXEN_BDINFO_VERSION); | ||
737 | rv = -1; | ||
738 | } | ||
739 | |||
740 | DPRINTK(INFO, "Discovered board type:0x%x ", boardinfo->board_type); | ||
741 | switch ((netxen_brdtype_t) boardinfo->board_type) { | ||
742 | case NETXEN_BRDTYPE_P2_SB35_4G: | ||
743 | adapter->ahw.board_type = NETXEN_NIC_GBE; | ||
744 | break; | ||
745 | case NETXEN_BRDTYPE_P2_SB31_10G: | ||
746 | case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ: | ||
747 | case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ: | ||
748 | case NETXEN_BRDTYPE_P2_SB31_10G_CX4: | ||
749 | adapter->ahw.board_type = NETXEN_NIC_XGBE; | ||
750 | break; | ||
751 | case NETXEN_BRDTYPE_P1_BD: | ||
752 | case NETXEN_BRDTYPE_P1_SB: | ||
753 | case NETXEN_BRDTYPE_P1_SMAX: | ||
754 | case NETXEN_BRDTYPE_P1_SOCK: | ||
755 | adapter->ahw.board_type = NETXEN_NIC_GBE; | ||
756 | break; | ||
757 | default: | ||
758 | printk("%s: Unknown(%x)\n", netxen_nic_driver_name, | ||
759 | boardinfo->board_type); | ||
760 | break; | ||
761 | } | ||
762 | |||
763 | return rv; | ||
764 | } | ||
765 | |||
766 | /* NIU access sections */ | ||
767 | |||
768 | int netxen_nic_set_mtu_gb(struct netxen_port *port, int new_mtu) | ||
769 | { | ||
770 | struct netxen_adapter *adapter = port->adapter; | ||
771 | netxen_nic_write_w0(adapter, | ||
772 | NETXEN_NIU_GB_MAX_FRAME_SIZE(port->portnum), | ||
773 | new_mtu); | ||
774 | return 0; | ||
775 | } | ||
776 | |||
777 | int netxen_nic_set_mtu_xgb(struct netxen_port *port, int new_mtu) | ||
778 | { | ||
779 | struct netxen_adapter *adapter = port->adapter; | ||
780 | new_mtu += NETXEN_NIU_HDRSIZE + NETXEN_NIU_TLRSIZE; | ||
781 | netxen_nic_write_w0(adapter, NETXEN_NIU_XGE_MAX_FRAME_SIZE, new_mtu); | ||
782 | return 0; | ||
783 | } | ||
784 | |||
785 | void netxen_nic_init_niu_gb(struct netxen_adapter *adapter) | ||
786 | { | ||
787 | int portno; | ||
788 | for (portno = 0; portno < NETXEN_NIU_MAX_GBE_PORTS; portno++) | ||
789 | netxen_niu_gbe_init_port(adapter, portno); | ||
790 | } | ||
791 | |||
792 | void netxen_nic_stop_all_ports(struct netxen_adapter *adapter) | ||
793 | { | ||
794 | int port_nr; | ||
795 | struct netxen_port *port; | ||
796 | |||
797 | for (port_nr = 0; port_nr < adapter->ahw.max_ports; port_nr++) { | ||
798 | port = adapter->port[port_nr]; | ||
799 | if (adapter->ops->stop_port) | ||
800 | adapter->ops->stop_port(adapter, port->portnum); | ||
801 | } | ||
802 | } | ||
803 | |||
804 | void | ||
805 | netxen_crb_writelit_adapter(struct netxen_adapter *adapter, unsigned long off, | ||
806 | int data) | ||
807 | { | ||
808 | void __iomem *addr; | ||
809 | |||
810 | if (ADDR_IN_WINDOW1(off)) { | ||
811 | writel(data, NETXEN_CRB_NORMALIZE(adapter, off)); | ||
812 | } else { | ||
813 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
814 | addr = (void __iomem *)(adapter->ahw.pci_base + off); | ||
815 | writel(data, addr); | ||
816 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
817 | } | ||
818 | } | ||
819 | |||
820 | void netxen_nic_set_link_parameters(struct netxen_port *port) | ||
821 | { | ||
822 | struct netxen_adapter *adapter = port->adapter; | ||
823 | __le32 status; | ||
824 | u16 autoneg; | ||
825 | __le32 mode; | ||
826 | |||
827 | netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode); | ||
828 | if (netxen_get_niu_enable_ge(mode)) { /* Gb 10/100/1000 Mbps mode */ | ||
829 | if (adapter->ops->phy_read | ||
830 | && adapter->ops-> | ||
831 | phy_read(adapter, port->portnum, | ||
832 | NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS, | ||
833 | &status) == 0) { | ||
834 | if (netxen_get_phy_link(status)) { | ||
835 | switch (netxen_get_phy_speed(status)) { | ||
836 | case 0: | ||
837 | port->link_speed = SPEED_10; | ||
838 | break; | ||
839 | case 1: | ||
840 | port->link_speed = SPEED_100; | ||
841 | break; | ||
842 | case 2: | ||
843 | port->link_speed = SPEED_1000; | ||
844 | break; | ||
845 | default: | ||
846 | port->link_speed = -1; | ||
847 | break; | ||
848 | } | ||
849 | switch (netxen_get_phy_duplex(status)) { | ||
850 | case 0: | ||
851 | port->link_duplex = DUPLEX_HALF; | ||
852 | break; | ||
853 | case 1: | ||
854 | port->link_duplex = DUPLEX_FULL; | ||
855 | break; | ||
856 | default: | ||
857 | port->link_duplex = -1; | ||
858 | break; | ||
859 | } | ||
860 | if (adapter->ops->phy_read | ||
861 | && adapter->ops-> | ||
862 | phy_read(adapter, port->portnum, | ||
863 | NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, | ||
864 | (__le32 *) & autoneg) != 0) | ||
865 | port->link_autoneg = autoneg; | ||
866 | } else | ||
867 | goto link_down; | ||
868 | } else { | ||
869 | link_down: | ||
870 | port->link_speed = -1; | ||
871 | port->link_duplex = -1; | ||
872 | } | ||
873 | } | ||
874 | } | ||
875 | |||
876 | void netxen_nic_flash_print(struct netxen_adapter *adapter) | ||
877 | { | ||
878 | int valid = 1; | ||
879 | u32 fw_major = 0; | ||
880 | u32 fw_minor = 0; | ||
881 | u32 fw_build = 0; | ||
882 | |||
883 | struct netxen_board_info *board_info = &(adapter->ahw.boardcfg); | ||
884 | if (board_info->magic != NETXEN_BDINFO_MAGIC) { | ||
885 | printk | ||
886 | ("NetXen Unknown board config, Read 0x%x expected as 0x%x\n", | ||
887 | board_info->magic, NETXEN_BDINFO_MAGIC); | ||
888 | valid = 0; | ||
889 | } | ||
890 | if (board_info->header_version != NETXEN_BDINFO_VERSION) { | ||
891 | printk("NetXen Unknown board config version." | ||
892 | " Read %x, expected %x\n", | ||
893 | board_info->header_version, NETXEN_BDINFO_VERSION); | ||
894 | valid = 0; | ||
895 | } | ||
896 | if (valid) { | ||
897 | printk("NetXen %s Board #%d, Chip id 0x%x\n", | ||
898 | board_info->board_type == 0x0b ? "XGB" : "GBE", | ||
899 | board_info->board_num, board_info->chip_id); | ||
900 | fw_major = readl(NETXEN_CRB_NORMALIZE(adapter, | ||
901 | NETXEN_FW_VERSION_MAJOR)); | ||
902 | fw_minor = readl(NETXEN_CRB_NORMALIZE(adapter, | ||
903 | NETXEN_FW_VERSION_MINOR)); | ||
904 | fw_build = | ||
905 | readl(NETXEN_CRB_NORMALIZE(adapter, NETXEN_FW_VERSION_SUB)); | ||
906 | |||
907 | printk("NetXen Firmware version %d.%d.%d\n", fw_major, fw_minor, | ||
908 | fw_build); | ||
909 | } | ||
910 | if (fw_major != _NETXEN_NIC_LINUX_MAJOR) { | ||
911 | printk(KERN_ERR "The mismatch in driver version and firmware " | ||
912 | "version major number\n" | ||
913 | "Driver version major number = %d \t" | ||
914 | "Firmware version major number = %d \n", | ||
915 | _NETXEN_NIC_LINUX_MAJOR, fw_major); | ||
916 | adapter->driver_mismatch = 1; | ||
917 | } | ||
918 | if (fw_minor != _NETXEN_NIC_LINUX_MINOR) { | ||
919 | printk(KERN_ERR "The mismatch in driver version and firmware " | ||
920 | "version minor number\n" | ||
921 | "Driver version minor number = %d \t" | ||
922 | "Firmware version minor number = %d \n", | ||
923 | _NETXEN_NIC_LINUX_MINOR, fw_minor); | ||
924 | adapter->driver_mismatch = 1; | ||
925 | } | ||
926 | if (adapter->driver_mismatch) | ||
927 | printk(KERN_INFO "Use the driver with version no %d.%d.xxx\n", | ||
928 | fw_major, fw_minor); | ||
929 | } | ||
930 | |||
931 | int netxen_crb_read_val(struct netxen_adapter *adapter, unsigned long off) | ||
932 | { | ||
933 | int data; | ||
934 | netxen_nic_hw_read_wx(adapter, off, &data, 4); | ||
935 | return data; | ||
936 | } | ||