aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/netxen/netxen_nic_hw.c
diff options
context:
space:
mode:
authorAmit S. Kale <amitkale@netxen.com>2006-12-04 12:23:25 -0500
committerJeff Garzik <jeff@garzik.org>2006-12-04 18:36:03 -0500
commited25ffa16434724f5ed825aa48734c7f3aefa203 (patch)
tree71cff36d0b2f43adf20e67ac6cc3ba3020f94ff2 /drivers/net/netxen/netxen_nic_hw.c
parent80922fbcb6f00127e91580e7565bb665947ac5d3 (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.c429
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
1007int 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
1083int 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
1154int 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
1227int 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}