diff options
author | Amit S. Kale <amitkale@netxen.com> | 2006-12-04 12:23:25 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-12-04 18:36:03 -0500 |
commit | ed25ffa16434724f5ed825aa48734c7f3aefa203 (patch) | |
tree | 71cff36d0b2f43adf20e67ac6cc3ba3020f94ff2 /drivers/net/netxen/netxen_nic_hw.c | |
parent | 80922fbcb6f00127e91580e7565bb665947ac5d3 (diff) |
[PATCH] NetXen: multiport firmware support, ioctl interface
NetXen: 1G/10G Ethernet driver updates
- Multiport and newer firmware support
- ioctl interface for user level tools
- Cast error fix for multiport
Signed-off-by: Amit S. Kale <amitkale@netxen.com>
netxen_nic.h | 281 +++++++++++++++++++++++++-------
netxen_nic_ethtool.c | 12 -
netxen_nic_hw.c | 429 +++++++++++++++++++++++++++++++++++++++++---------
netxen_nic_init.c | 301 ++++++++++++++++++++++++++++++-----
netxen_nic_ioctl.h | 2
netxen_nic_isr.c | 3
netxen_nic_main.c | 260 ++++++++++++++++++------------
netxen_nic_niu.c | 22 +-
netxen_nic_phan_reg.h | 228 ++++++++++++++++----------
9 files changed, 1161 insertions(+), 377 deletions(-)
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 | 429 |
1 files changed, 357 insertions, 72 deletions
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 7470852ab582..9147b6048dfb 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c | |||
@@ -42,7 +42,7 @@ | |||
42 | 42 | ||
43 | #define NETXEN_FLASH_BASE (BOOTLD_START) | 43 | #define NETXEN_FLASH_BASE (BOOTLD_START) |
44 | #define NETXEN_PHANTOM_MEM_BASE (NETXEN_FLASH_BASE) | 44 | #define NETXEN_PHANTOM_MEM_BASE (NETXEN_FLASH_BASE) |
45 | #define NETXEN_MAX_MTU 8000 | 45 | #define NETXEN_MAX_MTU 8000 + NETXEN_ENET_HEADER_SIZE + NETXEN_ETH_FCS_SIZE |
46 | #define NETXEN_MIN_MTU 64 | 46 | #define NETXEN_MIN_MTU 64 |
47 | #define NETXEN_ETH_FCS_SIZE 4 | 47 | #define NETXEN_ETH_FCS_SIZE 4 |
48 | #define NETXEN_ENET_HEADER_SIZE 14 | 48 | #define NETXEN_ENET_HEADER_SIZE 14 |
@@ -176,11 +176,9 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
176 | struct netxen_hardware_context *hw = &adapter->ahw; | 176 | struct netxen_hardware_context *hw = &adapter->ahw; |
177 | u32 state = 0; | 177 | u32 state = 0; |
178 | void *addr; | 178 | void *addr; |
179 | void *pause_addr; | ||
180 | int loops = 0, err = 0; | 179 | int loops = 0, err = 0; |
181 | int ctx, ring; | 180 | int ctx, ring; |
182 | u32 card_cmdring = 0; | 181 | u32 card_cmdring = 0; |
183 | struct netxen_rcv_desc_crb *rcv_desc_crb = NULL; | ||
184 | struct netxen_recv_context *recv_ctx; | 182 | struct netxen_recv_context *recv_ctx; |
185 | struct netxen_rcv_desc_ctx *rcv_desc; | 183 | struct netxen_rcv_desc_ctx *rcv_desc; |
186 | 184 | ||
@@ -224,33 +222,42 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
224 | DPRINTK(INFO, "Recieve Peg ready too. starting stuff\n"); | 222 | DPRINTK(INFO, "Recieve Peg ready too. starting stuff\n"); |
225 | 223 | ||
226 | addr = netxen_alloc(adapter->ahw.pdev, | 224 | addr = netxen_alloc(adapter->ahw.pdev, |
227 | sizeof(struct cmd_desc_type0) * | 225 | sizeof(struct netxen_ring_ctx) + |
228 | adapter->max_tx_desc_count, | 226 | sizeof(uint32_t), |
229 | &hw->cmd_desc_phys_addr, &hw->cmd_desc_pdev); | 227 | (dma_addr_t *) & adapter->ctx_desc_phys_addr, |
228 | &adapter->ctx_desc_pdev); | ||
230 | 229 | ||
230 | printk("ctx_desc_phys_addr: 0x%llx\n", | ||
231 | (u64) adapter->ctx_desc_phys_addr); | ||
231 | if (addr == NULL) { | 232 | if (addr == NULL) { |
232 | DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); | 233 | DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); |
233 | return -ENOMEM; | 234 | err = -ENOMEM; |
235 | return err; | ||
234 | } | 236 | } |
237 | memset(addr, 0, sizeof(struct netxen_ring_ctx)); | ||
238 | adapter->ctx_desc = (struct netxen_ring_ctx *)addr; | ||
239 | adapter->ctx_desc->cmd_consumer_offset = adapter->ctx_desc_phys_addr | ||
240 | + sizeof(struct netxen_ring_ctx); | ||
241 | adapter->cmd_consumer = (uint32_t *) (((char *)addr) + | ||
242 | sizeof(struct netxen_ring_ctx)); | ||
243 | |||
244 | addr = pci_alloc_consistent(adapter->ahw.pdev, | ||
245 | sizeof(struct cmd_desc_type0) * | ||
246 | adapter->max_tx_desc_count, | ||
247 | (dma_addr_t *) & hw->cmd_desc_phys_addr); | ||
248 | printk("cmd_desc_phys_addr: 0x%llx\n", (u64) hw->cmd_desc_phys_addr); | ||
235 | 249 | ||
236 | pause_addr = netxen_alloc(adapter->ahw.pdev, 512, | 250 | if (addr == NULL) { |
237 | (dma_addr_t *) & hw->pause_physaddr, | 251 | DPRINTK(ERR, "bad return from pci_alloc_consistent\n"); |
238 | &hw->pause_pdev); | 252 | netxen_free_hw_resources(adapter); |
239 | if (pause_addr == NULL) { | ||
240 | DPRINTK(1, ERR, "bad return from pci_alloc_consistent\n"); | ||
241 | return -ENOMEM; | 253 | return -ENOMEM; |
242 | } | 254 | } |
243 | 255 | ||
244 | hw->pauseaddr = (char *)pause_addr; | 256 | adapter->ctx_desc->cmd_ring_addr_lo = |
245 | { | 257 | hw->cmd_desc_phys_addr & 0xffffffffUL; |
246 | u64 *ptr = (u64 *) pause_addr; | 258 | adapter->ctx_desc->cmd_ring_addr_hi = |
247 | *ptr++ = NETXEN_NIC_ZERO_PAUSE_ADDR; | 259 | ((u64) hw->cmd_desc_phys_addr >> 32); |
248 | *ptr++ = NETXEN_NIC_ZERO_PAUSE_ADDR; | 260 | adapter->ctx_desc->cmd_ring_size = adapter->max_tx_desc_count; |
249 | *ptr++ = NETXEN_NIC_UNIT_PAUSE_ADDR; | ||
250 | *ptr++ = NETXEN_NIC_ZERO_PAUSE_ADDR; | ||
251 | *ptr++ = NETXEN_NIC_EPG_PAUSE_ADDR1; | ||
252 | *ptr++ = NETXEN_NIC_EPG_PAUSE_ADDR2; | ||
253 | } | ||
254 | 261 | ||
255 | hw->cmd_desc_head = (struct cmd_desc_type0 *)addr; | 262 | hw->cmd_desc_head = (struct cmd_desc_type0 *)addr; |
256 | 263 | ||
@@ -271,6 +278,12 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
271 | return err; | 278 | return err; |
272 | } | 279 | } |
273 | rcv_desc->desc_head = (struct rcv_desc *)addr; | 280 | rcv_desc->desc_head = (struct rcv_desc *)addr; |
281 | adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr_lo = | ||
282 | rcv_desc->phys_addr & 0xffffffffUL; | ||
283 | adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr_hi = | ||
284 | ((u64) rcv_desc->phys_addr >> 32); | ||
285 | adapter->ctx_desc->rcv_ctx[ring].rcv_ring_size = | ||
286 | rcv_desc->max_rx_desc_count; | ||
274 | } | 287 | } |
275 | 288 | ||
276 | addr = netxen_alloc(adapter->ahw.pdev, STATUS_DESC_RINGSIZE, | 289 | addr = netxen_alloc(adapter->ahw.pdev, STATUS_DESC_RINGSIZE, |
@@ -284,47 +297,21 @@ int netxen_nic_hw_resources(struct netxen_adapter *adapter) | |||
284 | return err; | 297 | return err; |
285 | } | 298 | } |
286 | recv_ctx->rcv_status_desc_head = (struct status_desc *)addr; | 299 | recv_ctx->rcv_status_desc_head = (struct status_desc *)addr; |
287 | for (ring = 0; ring < NUM_RCV_DESC_RINGS; ring++) { | 300 | adapter->ctx_desc->sts_ring_addr_lo = |
288 | rcv_desc = &recv_ctx->rcv_desc[ring]; | 301 | recv_ctx->rcv_status_desc_phys_addr & 0xffffffffUL; |
289 | rcv_desc_crb = | 302 | adapter->ctx_desc->sts_ring_addr_hi = |
290 | &recv_crb_registers[ctx].rcv_desc_crb[ring]; | 303 | ((u64) recv_ctx->rcv_status_desc_phys_addr >> 32); |
291 | DPRINTK(INFO, "ring #%d crb global ring reg 0x%x\n", | 304 | adapter->ctx_desc->sts_ring_size = adapter->max_rx_desc_count; |
292 | ring, rcv_desc_crb->crb_globalrcv_ring); | ||
293 | /* Window = 1 */ | ||
294 | writel(lower32(rcv_desc->phys_addr), | ||
295 | NETXEN_CRB_NORMALIZE(adapter, | ||
296 | rcv_desc_crb-> | ||
297 | crb_globalrcv_ring)); | ||
298 | DPRINTK(INFO, "GLOBAL_RCV_RING ctx %d, addr 0x%x" | ||
299 | " val 0x%llx," | ||
300 | " virt %p\n", ctx, | ||
301 | rcv_desc_crb->crb_globalrcv_ring, | ||
302 | (unsigned long long)rcv_desc->phys_addr, | ||
303 | +rcv_desc->desc_head); | ||
304 | } | ||
305 | 305 | ||
306 | /* Window = 1 */ | ||
307 | writel(lower32(recv_ctx->rcv_status_desc_phys_addr), | ||
308 | NETXEN_CRB_NORMALIZE(adapter, | ||
309 | recv_crb_registers[ctx]. | ||
310 | crb_rcvstatus_ring)); | ||
311 | DPRINTK(INFO, "RCVSTATUS_RING, ctx %d, addr 0x%x," | ||
312 | " val 0x%x,virt%p\n", | ||
313 | ctx, | ||
314 | recv_crb_registers[ctx].crb_rcvstatus_ring, | ||
315 | (unsigned long long)recv_ctx->rcv_status_desc_phys_addr, | ||
316 | recv_ctx->rcv_status_desc_head); | ||
317 | } | 306 | } |
318 | /* Window = 1 */ | 307 | /* Window = 1 */ |
319 | writel(lower32(hw->pause_physaddr), | 308 | |
320 | NETXEN_CRB_NORMALIZE(adapter, CRB_PAUSE_ADDR_LO)); | 309 | writel(lower32(adapter->ctx_desc_phys_addr), |
321 | writel(upper32(hw->pause_physaddr), | 310 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_LO)); |
322 | NETXEN_CRB_NORMALIZE(adapter, CRB_PAUSE_ADDR_HI)); | 311 | writel(upper32(adapter->ctx_desc_phys_addr), |
323 | 312 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_ADDR_REG_HI)); | |
324 | writel(lower32(hw->cmd_desc_phys_addr), | 313 | writel(NETXEN_CTX_SIGNATURE, |
325 | NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_LO)); | 314 | NETXEN_CRB_NORMALIZE(adapter, CRB_CTX_SIGNATURE_REG)); |
326 | writel(upper32(hw->cmd_desc_phys_addr), | ||
327 | NETXEN_CRB_NORMALIZE(adapter, CRB_HOST_CMD_ADDR_HI)); | ||
328 | return err; | 315 | return err; |
329 | } | 316 | } |
330 | 317 | ||
@@ -334,6 +321,15 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) | |||
334 | struct netxen_rcv_desc_ctx *rcv_desc; | 321 | struct netxen_rcv_desc_ctx *rcv_desc; |
335 | int ctx, ring; | 322 | int ctx, ring; |
336 | 323 | ||
324 | if (adapter->ctx_desc != NULL) { | ||
325 | pci_free_consistent(adapter->ctx_desc_pdev, | ||
326 | sizeof(struct netxen_ring_ctx) + | ||
327 | sizeof(uint32_t), | ||
328 | adapter->ctx_desc, | ||
329 | adapter->ctx_desc_phys_addr); | ||
330 | adapter->ctx_desc = NULL; | ||
331 | } | ||
332 | |||
337 | if (adapter->ahw.cmd_desc_head != NULL) { | 333 | if (adapter->ahw.cmd_desc_head != NULL) { |
338 | pci_free_consistent(adapter->ahw.cmd_desc_pdev, | 334 | pci_free_consistent(adapter->ahw.cmd_desc_pdev, |
339 | sizeof(struct cmd_desc_type0) * | 335 | sizeof(struct cmd_desc_type0) * |
@@ -342,11 +338,9 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter) | |||
342 | adapter->ahw.cmd_desc_phys_addr); | 338 | adapter->ahw.cmd_desc_phys_addr); |
343 | adapter->ahw.cmd_desc_head = NULL; | 339 | adapter->ahw.cmd_desc_head = NULL; |
344 | } | 340 | } |
345 | if (adapter->ahw.pauseaddr != NULL) { | 341 | /* Special handling: there are 2 ports on this board */ |
346 | pci_free_consistent(adapter->ahw.pause_pdev, 512, | 342 | if (adapter->ahw.boardcfg.board_type == NETXEN_BRDTYPE_P2_SB31_10G_IMEZ) { |
347 | adapter->ahw.pauseaddr, | 343 | adapter->ahw.max_ports = 2; |
348 | adapter->ahw.pause_physaddr); | ||
349 | adapter->ahw.pauseaddr = NULL; | ||
350 | } | 344 | } |
351 | 345 | ||
352 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { | 346 | for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) { |
@@ -381,19 +375,22 @@ void netxen_tso_check(struct netxen_adapter *adapter, | |||
381 | desc->total_hdr_length = sizeof(struct ethhdr) + | 375 | desc->total_hdr_length = sizeof(struct ethhdr) + |
382 | ((skb->nh.iph)->ihl * sizeof(u32)) + | 376 | ((skb->nh.iph)->ihl * sizeof(u32)) + |
383 | ((skb->h.th)->doff * sizeof(u32)); | 377 | ((skb->h.th)->doff * sizeof(u32)); |
384 | desc->opcode = TX_TCP_LSO; | 378 | netxen_set_cmd_desc_opcode(desc, TX_TCP_LSO); |
385 | } else if (skb->ip_summed == CHECKSUM_COMPLETE) { | 379 | } else if (skb->ip_summed == CHECKSUM_COMPLETE) { |
386 | if (skb->nh.iph->protocol == IPPROTO_TCP) { | 380 | if (skb->nh.iph->protocol == IPPROTO_TCP) { |
387 | desc->opcode = TX_TCP_PKT; | 381 | netxen_set_cmd_desc_opcode(desc, TX_TCP_PKT); |
388 | } else if (skb->nh.iph->protocol == IPPROTO_UDP) { | 382 | } else if (skb->nh.iph->protocol == IPPROTO_UDP) { |
389 | desc->opcode = TX_UDP_PKT; | 383 | netxen_set_cmd_desc_opcode(desc, TX_UDP_PKT); |
390 | } else { | 384 | } else { |
391 | return; | 385 | return; |
392 | } | 386 | } |
393 | } | 387 | } |
394 | adapter->stats.xmitcsummed++; | 388 | adapter->stats.xmitcsummed++; |
395 | CMD_DESC_TCP_HDR_OFFSET_WRT(desc, skb->h.raw - skb->data); | 389 | desc->tcp_hdr_offset = skb->h.raw - skb->data; |
396 | desc->length_tcp_hdr = cpu_to_le32(desc->length_tcp_hdr); | 390 | netxen_set_cmd_desc_totallength(desc, |
391 | cpu_to_le32 | ||
392 | (netxen_get_cmd_desc_totallength | ||
393 | (desc))); | ||
397 | desc->ip_hdr_offset = skb->nh.raw - skb->data; | 394 | desc->ip_hdr_offset = skb->nh.raw - skb->data; |
398 | } | 395 | } |
399 | 396 | ||
@@ -871,7 +868,7 @@ void netxen_nic_set_link_parameters(struct netxen_port *port) | |||
871 | { | 868 | { |
872 | struct netxen_adapter *adapter = port->adapter; | 869 | struct netxen_adapter *adapter = port->adapter; |
873 | __le32 status; | 870 | __le32 status; |
874 | u16 autoneg; | 871 | __le32 autoneg; |
875 | __le32 mode; | 872 | __le32 mode; |
876 | 873 | ||
877 | netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode); | 874 | netxen_nic_read_w0(adapter, NETXEN_NIU_MODE, &mode); |
@@ -911,7 +908,7 @@ void netxen_nic_set_link_parameters(struct netxen_port *port) | |||
911 | && adapter-> | 908 | && adapter-> |
912 | phy_read(adapter, port->portnum, | 909 | phy_read(adapter, port->portnum, |
913 | NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, | 910 | NETXEN_NIU_GB_MII_MGMT_ADDR_AUTONEG, |
914 | (__le32 *) & autoneg) != 0) | 911 | &autoneg) != 0) |
915 | port->link_autoneg = autoneg; | 912 | port->link_autoneg = autoneg; |
916 | } else | 913 | } else |
917 | goto link_down; | 914 | goto link_down; |
@@ -1006,3 +1003,291 @@ int netxen_crb_read_val(struct netxen_adapter *adapter, unsigned long off) | |||
1006 | netxen_nic_hw_read_wx(adapter, off, &data, 4); | 1003 | netxen_nic_hw_read_wx(adapter, off, &data, 4); |
1007 | return data; | 1004 | return data; |
1008 | } | 1005 | } |
1006 | |||
1007 | int netxen_nic_hw_write_ioctl(struct netxen_adapter *adapter, u64 off, | ||
1008 | void *data, int len) | ||
1009 | { | ||
1010 | void *addr; | ||
1011 | u64 offset = off; | ||
1012 | u8 *mem_ptr = NULL; | ||
1013 | unsigned long mem_base; | ||
1014 | unsigned long mem_page; | ||
1015 | |||
1016 | if (ADDR_IN_WINDOW1(off)) { | ||
1017 | addr = NETXEN_CRB_NORMALIZE(adapter, off); | ||
1018 | if (!addr) { | ||
1019 | mem_base = pci_resource_start(adapter->ahw.pdev, 0); | ||
1020 | offset = NETXEN_CRB_NORMAL(off); | ||
1021 | mem_page = offset & PAGE_MASK; | ||
1022 | if (mem_page != ((offset + len - 1) & PAGE_MASK)) | ||
1023 | mem_ptr = | ||
1024 | ioremap(mem_base + mem_page, PAGE_SIZE * 2); | ||
1025 | else | ||
1026 | mem_ptr = | ||
1027 | ioremap(mem_base + mem_page, PAGE_SIZE); | ||
1028 | if (mem_ptr == 0UL) { | ||
1029 | return 1; | ||
1030 | } | ||
1031 | addr = mem_ptr; | ||
1032 | addr += offset & (PAGE_SIZE - 1); | ||
1033 | } | ||
1034 | } else { | ||
1035 | addr = pci_base_offset(adapter, off); | ||
1036 | if (!addr) { | ||
1037 | mem_base = pci_resource_start(adapter->ahw.pdev, 0); | ||
1038 | mem_page = off & PAGE_MASK; | ||
1039 | if (mem_page != ((off + len - 1) & PAGE_MASK)) | ||
1040 | mem_ptr = | ||
1041 | ioremap(mem_base + mem_page, PAGE_SIZE * 2); | ||
1042 | else | ||
1043 | mem_ptr = | ||
1044 | ioremap(mem_base + mem_page, PAGE_SIZE); | ||
1045 | if (mem_ptr == 0UL) { | ||
1046 | return 1; | ||
1047 | } | ||
1048 | addr = mem_ptr; | ||
1049 | addr += off & (PAGE_SIZE - 1); | ||
1050 | } | ||
1051 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
1052 | } | ||
1053 | switch (len) { | ||
1054 | case 1: | ||
1055 | writeb(*(u8 *) data, addr); | ||
1056 | break; | ||
1057 | case 2: | ||
1058 | writew(*(u16 *) data, addr); | ||
1059 | break; | ||
1060 | case 4: | ||
1061 | writel(*(u32 *) data, addr); | ||
1062 | break; | ||
1063 | case 8: | ||
1064 | writeq(*(u64 *) data, addr); | ||
1065 | break; | ||
1066 | default: | ||
1067 | DPRINTK(INFO, | ||
1068 | "writing data %lx to offset %llx, num words=%d\n", | ||
1069 | *(unsigned long *)data, off, (len >> 3)); | ||
1070 | |||
1071 | netxen_nic_hw_block_write64((u64 __iomem *) data, addr, | ||
1072 | (len >> 3)); | ||
1073 | break; | ||
1074 | } | ||
1075 | |||
1076 | if (!ADDR_IN_WINDOW1(off)) | ||
1077 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
1078 | if (mem_ptr) | ||
1079 | iounmap(mem_ptr); | ||
1080 | return 0; | ||
1081 | } | ||
1082 | |||
1083 | int netxen_nic_hw_read_ioctl(struct netxen_adapter *adapter, u64 off, | ||
1084 | void *data, int len) | ||
1085 | { | ||
1086 | void *addr; | ||
1087 | u64 offset; | ||
1088 | u8 *mem_ptr = NULL; | ||
1089 | unsigned long mem_base; | ||
1090 | unsigned long mem_page; | ||
1091 | |||
1092 | if (ADDR_IN_WINDOW1(off)) { | ||
1093 | addr = NETXEN_CRB_NORMALIZE(adapter, off); | ||
1094 | if (!addr) { | ||
1095 | mem_base = pci_resource_start(adapter->ahw.pdev, 0); | ||
1096 | offset = NETXEN_CRB_NORMAL(off); | ||
1097 | mem_page = offset & PAGE_MASK; | ||
1098 | if (mem_page != ((offset + len - 1) & PAGE_MASK)) | ||
1099 | mem_ptr = | ||
1100 | ioremap(mem_base + mem_page, PAGE_SIZE * 2); | ||
1101 | else | ||
1102 | mem_ptr = | ||
1103 | ioremap(mem_base + mem_page, PAGE_SIZE); | ||
1104 | if (mem_ptr == 0UL) { | ||
1105 | *(u8 *) data = 0; | ||
1106 | return 1; | ||
1107 | } | ||
1108 | addr = mem_ptr; | ||
1109 | addr += offset & (PAGE_SIZE - 1); | ||
1110 | } | ||
1111 | } else { | ||
1112 | addr = pci_base_offset(adapter, off); | ||
1113 | if (!addr) { | ||
1114 | mem_base = pci_resource_start(adapter->ahw.pdev, 0); | ||
1115 | mem_page = off & PAGE_MASK; | ||
1116 | if (mem_page != ((off + len - 1) & PAGE_MASK)) | ||
1117 | mem_ptr = | ||
1118 | ioremap(mem_base + mem_page, PAGE_SIZE * 2); | ||
1119 | else | ||
1120 | mem_ptr = | ||
1121 | ioremap(mem_base + mem_page, PAGE_SIZE); | ||
1122 | if (mem_ptr == 0UL) | ||
1123 | return 1; | ||
1124 | addr = mem_ptr; | ||
1125 | addr += off & (PAGE_SIZE - 1); | ||
1126 | } | ||
1127 | netxen_nic_pci_change_crbwindow(adapter, 0); | ||
1128 | } | ||
1129 | switch (len) { | ||
1130 | case 1: | ||
1131 | *(u8 *) data = readb(addr); | ||
1132 | break; | ||
1133 | case 2: | ||
1134 | *(u16 *) data = readw(addr); | ||
1135 | break; | ||
1136 | case 4: | ||
1137 | *(u32 *) data = readl(addr); | ||
1138 | break; | ||
1139 | case 8: | ||
1140 | *(u64 *) data = readq(addr); | ||
1141 | break; | ||
1142 | default: | ||
1143 | netxen_nic_hw_block_read64((u64 __iomem *) data, addr, | ||
1144 | (len >> 3)); | ||
1145 | break; | ||
1146 | } | ||
1147 | if (!ADDR_IN_WINDOW1(off)) | ||
1148 | netxen_nic_pci_change_crbwindow(adapter, 1); | ||
1149 | if (mem_ptr) | ||
1150 | iounmap(mem_ptr); | ||
1151 | return 0; | ||
1152 | } | ||
1153 | |||
1154 | int netxen_nic_pci_mem_write_ioctl(struct netxen_adapter *adapter, u64 off, | ||
1155 | void *data, int size) | ||
1156 | { | ||
1157 | void *addr; | ||
1158 | int ret = 0; | ||
1159 | u8 *mem_ptr = NULL; | ||
1160 | unsigned long mem_base; | ||
1161 | unsigned long mem_page; | ||
1162 | |||
1163 | if (data == NULL || off > (128 * 1024 * 1024)) { | ||
1164 | printk(KERN_ERR "%s: data: %p off:%llx\n", | ||
1165 | netxen_nic_driver_name, data, off); | ||
1166 | return 1; | ||
1167 | } | ||
1168 | off = netxen_nic_pci_set_window(adapter, off); | ||
1169 | /* Corner case : Malicious user tried to break the driver by reading | ||
1170 | last few bytes in ranges and tries to read further addresses. | ||
1171 | */ | ||
1172 | if (!pci_base(adapter, off + size - 1) && pci_base(adapter, off)) { | ||
1173 | printk(KERN_ERR "%s: Invalid access to memory address range" | ||
1174 | " 0x%llx - 0x%llx\n", netxen_nic_driver_name, off, | ||
1175 | off + size); | ||
1176 | return 1; | ||
1177 | } | ||
1178 | addr = pci_base_offset(adapter, off); | ||
1179 | DPRINTK(INFO, "writing data %llx to offset %llx\n", | ||
1180 | *(unsigned long long *)data, off); | ||
1181 | if (!addr) { | ||
1182 | mem_base = pci_resource_start(adapter->ahw.pdev, 0); | ||
1183 | mem_page = off & PAGE_MASK; | ||
1184 | /* Map two pages whenever user tries to access addresses in two | ||
1185 | consecutive pages. | ||
1186 | */ | ||
1187 | if (mem_page != ((off + size - 1) & PAGE_MASK)) | ||
1188 | mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); | ||
1189 | else | ||
1190 | mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); | ||
1191 | if (mem_ptr == 0UL) { | ||
1192 | return 1; | ||
1193 | } | ||
1194 | addr = mem_ptr; | ||
1195 | addr += off & (PAGE_SIZE - 1); | ||
1196 | } | ||
1197 | switch (size) { | ||
1198 | case 1: | ||
1199 | writeb(*(u8 *) data, addr); | ||
1200 | break; | ||
1201 | case 2: | ||
1202 | writew(*(u16 *) data, addr); | ||
1203 | break; | ||
1204 | case 4: | ||
1205 | writel(*(u32 *) data, addr); | ||
1206 | break; | ||
1207 | case 8: | ||
1208 | writeq(*(u64 *) data, addr); | ||
1209 | break; | ||
1210 | default: | ||
1211 | DPRINTK(INFO, | ||
1212 | "writing data %lx to offset %llx, num words=%d\n", | ||
1213 | *(unsigned long *)data, off, (size >> 3)); | ||
1214 | |||
1215 | netxen_nic_hw_block_write64((u64 __iomem *) data, addr, | ||
1216 | (size >> 3)); | ||
1217 | break; | ||
1218 | } | ||
1219 | |||
1220 | if (mem_ptr) | ||
1221 | iounmap(mem_ptr); | ||
1222 | DPRINTK(INFO, "wrote %llx\n", *(unsigned long long *)data); | ||
1223 | |||
1224 | return ret; | ||
1225 | } | ||
1226 | |||
1227 | int netxen_nic_pci_mem_read_ioctl(struct netxen_adapter *adapter, | ||
1228 | u64 off, void *data, int size) | ||
1229 | { | ||
1230 | void *addr; | ||
1231 | int ret = 0; | ||
1232 | u8 *mem_ptr = NULL; | ||
1233 | unsigned long mem_base; | ||
1234 | unsigned long mem_page; | ||
1235 | |||
1236 | if (data == NULL || off > (128 * 1024 * 1024)) { | ||
1237 | printk(KERN_ERR "%s: data: %p off:%llx\n", | ||
1238 | netxen_nic_driver_name, data, off); | ||
1239 | return 1; | ||
1240 | } | ||
1241 | off = netxen_nic_pci_set_window(adapter, off); | ||
1242 | /* Corner case : Malicious user tried to break the driver by reading | ||
1243 | last few bytes in ranges and tries to read further addresses. | ||
1244 | */ | ||
1245 | if (!pci_base(adapter, off + size - 1) && pci_base(adapter, off)) { | ||
1246 | printk(KERN_ERR "%s: Invalid access to memory address range" | ||
1247 | " 0x%llx - 0x%llx\n", netxen_nic_driver_name, off, | ||
1248 | off + size); | ||
1249 | return 1; | ||
1250 | } | ||
1251 | addr = pci_base_offset(adapter, off); | ||
1252 | if (!addr) { | ||
1253 | mem_base = pci_resource_start(adapter->ahw.pdev, 0); | ||
1254 | mem_page = off & PAGE_MASK; | ||
1255 | /* Map two pages whenever user tries to access addresses in two | ||
1256 | consecutive pages. | ||
1257 | */ | ||
1258 | if (mem_page != ((off + size - 1) & PAGE_MASK)) | ||
1259 | mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); | ||
1260 | else | ||
1261 | mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); | ||
1262 | if (mem_ptr == 0UL) { | ||
1263 | *(u8 *) data = 0; | ||
1264 | return 1; | ||
1265 | } | ||
1266 | addr = mem_ptr; | ||
1267 | addr += off & (PAGE_SIZE - 1); | ||
1268 | } | ||
1269 | switch (size) { | ||
1270 | case 1: | ||
1271 | *(u8 *) data = readb(addr); | ||
1272 | break; | ||
1273 | case 2: | ||
1274 | *(u16 *) data = readw(addr); | ||
1275 | break; | ||
1276 | case 4: | ||
1277 | *(u32 *) data = readl(addr); | ||
1278 | break; | ||
1279 | case 8: | ||
1280 | *(u64 *) data = readq(addr); | ||
1281 | break; | ||
1282 | default: | ||
1283 | netxen_nic_hw_block_read64((u64 __iomem *) data, addr, | ||
1284 | (size >> 3)); | ||
1285 | break; | ||
1286 | } | ||
1287 | |||
1288 | if (mem_ptr) | ||
1289 | iounmap(mem_ptr); | ||
1290 | DPRINTK(INFO, "read %llx\n", *(unsigned long long *)data); | ||
1291 | |||
1292 | return ret; | ||
1293 | } | ||