[PATCH] IB/ipath - program intconfig register using new HT irq hook

Eric's changes to the htirq infrastructure require corresponding
modifications to the ipath HT driver code so that interrupts are still
delivered properly.

Signed-off-by: Bryan O'Sullivan <bryan.osullivan@qlogic.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Roland Dreier <rdreier@cisco.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Bryan O'Sullivan and committed by Linus Torvalds 51f65ebc 43539c38

+74 -82
+8 -9
drivers/infiniband/hw/ipath/ipath_driver.c
··· 304 304 } 305 305 addr = pci_resource_start(pdev, 0); 306 306 len = pci_resource_len(pdev, 0); 307 - ipath_cdbg(VERBOSE, "regbase (0) %llx len %d irq %x, vend %x/%x " 307 + ipath_cdbg(VERBOSE, "regbase (0) %llx len %d pdev->irq %d, vend %x/%x " 308 308 "driver_data %lx\n", addr, len, pdev->irq, ent->vendor, 309 309 ent->device, ent->driver_data); 310 310 ··· 467 467 * check 0 irq after we return from chip-specific bus setup, since 468 468 * that can affect this due to setup 469 469 */ 470 - if (!pdev->irq) 470 + if (!dd->ipath_irq) 471 471 ipath_dev_err(dd, "irq is 0, BIOS error? Interrupts won't " 472 472 "work\n"); 473 473 else { 474 - ret = request_irq(pdev->irq, ipath_intr, IRQF_SHARED, 474 + ret = request_irq(dd->ipath_irq, ipath_intr, IRQF_SHARED, 475 475 IPATH_DRV_NAME, dd); 476 476 if (ret) { 477 477 ipath_dev_err(dd, "Couldn't setup irq handler, " 478 - "irq=%u: %d\n", pdev->irq, ret); 478 + "irq=%d: %d\n", dd->ipath_irq, ret); 479 479 goto bail_iounmap; 480 480 } 481 481 } ··· 637 637 * free up port 0 (kernel) rcvhdr, egr bufs, and eventually tid bufs 638 638 * for all versions of the driver, if they were allocated 639 639 */ 640 - if (pdev->irq) { 641 - ipath_cdbg(VERBOSE, 642 - "unit %u free_irq of irq %x\n", 643 - dd->ipath_unit, pdev->irq); 644 - free_irq(pdev->irq, dd); 640 + if (dd->ipath_irq) { 641 + ipath_cdbg(VERBOSE, "unit %u free irq %d\n", 642 + dd->ipath_unit, dd->ipath_irq); 643 + dd->ipath_f_free_irq(dd); 645 644 } else 646 645 ipath_dbg("irq is 0, not doing free_irq " 647 646 "for unit %u\n", dd->ipath_unit);
+49 -68
drivers/infiniband/hw/ipath/ipath_iba6110.c
··· 38 38 39 39 #include <linux/pci.h> 40 40 #include <linux/delay.h> 41 + #include <linux/htirq.h> 41 42 42 43 #include "ipath_kernel.h" 43 44 #include "ipath_registers.h" ··· 914 913 } 915 914 } 916 915 917 - static int set_int_handler(struct ipath_devdata *dd, struct pci_dev *pdev, 918 - int pos) 916 + static int ipath_ht_intconfig(struct ipath_devdata *dd) 919 917 { 920 - u32 int_handler_addr_lower; 921 - u32 int_handler_addr_upper; 922 - u64 ihandler; 923 - u32 intvec; 918 + int ret; 924 919 925 - /* use indirection register to get the intr handler */ 926 - pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x10); 927 - pci_read_config_dword(pdev, pos + 4, &int_handler_addr_lower); 928 - pci_write_config_byte(pdev, pos + HT_INTR_REG_INDEX, 0x11); 929 - pci_read_config_dword(pdev, pos + 4, &int_handler_addr_upper); 920 + if (dd->ipath_intconfig) { 921 + ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig, 922 + dd->ipath_intconfig); /* interrupt address */ 923 + ret = 0; 924 + } else { 925 + ipath_dev_err(dd, "No interrupts enabled, couldn't setup " 926 + "interrupt address\n"); 927 + ret = -EINVAL; 928 + } 930 929 931 - ihandler = (u64) int_handler_addr_lower | 932 - ((u64) int_handler_addr_upper << 32); 930 + return ret; 931 + } 932 + 933 + static void ipath_ht_irq_update(struct pci_dev *dev, int irq, 934 + struct ht_irq_msg *msg) 935 + { 936 + struct ipath_devdata *dd = pci_get_drvdata(dev); 937 + u64 prev_intconfig = dd->ipath_intconfig; 938 + 939 + dd->ipath_intconfig = msg->address_lo; 940 + dd->ipath_intconfig |= ((u64) msg->address_hi) << 32; 933 941 934 942 /* 935 - * kernels with CONFIG_PCI_MSI set the vector in the irq field of 936 - * struct pci_device, so we use that to program the internal 937 - * interrupt register (not config space) with that value. The BIOS 938 - * must still have done the basic MSI setup. 943 + * If the previous value of dd->ipath_intconfig is zero, we're 944 + * getting configured for the first time, and must not program the 945 + * intconfig register here (it will be programmed later, when the 946 + * hardware is ready). Otherwise, we should. 939 947 */ 940 - intvec = pdev->irq; 941 - /* 942 - * clear any vector bits there; normally not set but we'll overload 943 - * this for some debug purposes (setting the HTC debug register 944 - * value from software, rather than GPIOs), so it might be set on a 945 - * driver reload. 946 - */ 947 - ihandler &= ~0xff0000; 948 - /* x86 vector goes in intrinfo[23:16] */ 949 - ihandler |= intvec << 16; 950 - ipath_cdbg(VERBOSE, "ihandler lower %x, upper %x, intvec %x, " 951 - "interruptconfig %llx\n", int_handler_addr_lower, 952 - int_handler_addr_upper, intvec, 953 - (unsigned long long) ihandler); 954 - 955 - /* can't program yet, so save for interrupt setup */ 956 - dd->ipath_intconfig = ihandler; 957 - /* keep going, so we find link control stuff also */ 958 - 959 - return ihandler != 0; 948 + if (prev_intconfig) 949 + ipath_ht_intconfig(dd); 960 950 } 961 951 962 952 /** ··· 963 971 static int ipath_setup_ht_config(struct ipath_devdata *dd, 964 972 struct pci_dev *pdev) 965 973 { 966 - int pos, ret = 0; 967 - int ihandler = 0; 974 + int pos, ret; 975 + 976 + ret = __ht_create_irq(pdev, 0, ipath_ht_irq_update); 977 + if (ret < 0) { 978 + ipath_dev_err(dd, "Couldn't create interrupt handler: " 979 + "err %d\n", ret); 980 + goto bail; 981 + } 982 + dd->ipath_irq = ret; 983 + ret = 0; 968 984 969 985 /* 970 - * Read the capability info to find the interrupt info, and also 971 - * handle clearing CRC errors in linkctrl register if necessary. We 986 + * Handle clearing CRC errors in linkctrl register if necessary. We 972 987 * do this early, before we ever enable errors or hardware errors, 973 988 * mostly to avoid causing the chip to enter freeze mode. 974 989 */ ··· 999 1000 } 1000 1001 if (!(cap_type & 0xE0)) 1001 1002 slave_or_pri_blk(dd, pdev, pos, cap_type); 1002 - else if (cap_type == HT_INTR_DISC_CONFIG) 1003 - ihandler = set_int_handler(dd, pdev, pos); 1004 1003 } while ((pos = pci_find_next_capability(pdev, pos, 1005 1004 PCI_CAP_ID_HT))); 1006 - 1007 - if (!ihandler) { 1008 - ipath_dev_err(dd, "Couldn't find interrupt handler in " 1009 - "config space\n"); 1010 - ret = -ENODEV; 1011 - } 1012 1005 1013 1006 bail: 1014 1007 return ret; ··· 1351 1360 ipath_write_kreg(dd, dd->ipath_kregs->kr_serdesconfig0, val); 1352 1361 } 1353 1362 1354 - static int ipath_ht_intconfig(struct ipath_devdata *dd) 1355 - { 1356 - int ret; 1357 - 1358 - if (!dd->ipath_intconfig) { 1359 - ipath_dev_err(dd, "No interrupts enabled, couldn't setup " 1360 - "interrupt address\n"); 1361 - ret = 1; 1362 - goto bail; 1363 - } 1364 - 1365 - ipath_write_kreg(dd, dd->ipath_kregs->kr_interruptconfig, 1366 - dd->ipath_intconfig); /* interrupt address */ 1367 - ret = 0; 1368 - 1369 - bail: 1370 - return ret; 1371 - } 1372 - 1373 1363 /** 1374 1364 * ipath_pe_put_tid - write a TID in chip 1375 1365 * @dd: the infinipath device ··· 1547 1575 return 0; 1548 1576 } 1549 1577 1578 + static void ipath_ht_free_irq(struct ipath_devdata *dd) 1579 + { 1580 + free_irq(dd->ipath_irq, dd); 1581 + ht_destroy_irq(dd->ipath_irq); 1582 + dd->ipath_irq = 0; 1583 + dd->ipath_intconfig = 0; 1584 + } 1585 + 1550 1586 /** 1551 1587 * ipath_init_iba6110_funcs - set up the chip-specific function pointers 1552 1588 * @dd: the infinipath device ··· 1578 1598 dd->ipath_f_cleanup = ipath_setup_ht_cleanup; 1579 1599 dd->ipath_f_setextled = ipath_setup_ht_setextled; 1580 1600 dd->ipath_f_get_base_info = ipath_ht_get_base_info; 1601 + dd->ipath_f_free_irq = ipath_ht_free_irq; 1581 1602 1582 1603 /* 1583 1604 * initialize chip-specific variables
+8
drivers/infiniband/hw/ipath/ipath_iba6120.c
··· 851 851 int pos, ret; 852 852 853 853 dd->ipath_msi_lo = 0; /* used as a flag during reset processing */ 854 + dd->ipath_irq = pdev->irq; 854 855 ret = pci_enable_msi(dd->pcidev); 855 856 if (ret) 856 857 ipath_dev_err(dd, "pci_enable_msi failed: %d, " ··· 1324 1323 return 0; 1325 1324 } 1326 1325 1326 + static void ipath_pe_free_irq(struct ipath_devdata *dd) 1327 + { 1328 + free_irq(dd->ipath_irq, dd); 1329 + dd->ipath_irq = 0; 1330 + } 1331 + 1327 1332 /** 1328 1333 * ipath_init_iba6120_funcs - set up the chip-specific function pointers 1329 1334 * @dd: the infinipath device ··· 1356 1349 dd->ipath_f_cleanup = ipath_setup_pe_cleanup; 1357 1350 dd->ipath_f_setextled = ipath_setup_pe_setextled; 1358 1351 dd->ipath_f_get_base_info = ipath_pe_get_base_info; 1352 + dd->ipath_f_free_irq = ipath_pe_free_irq; 1359 1353 1360 1354 /* initialize chip-specific variables */ 1361 1355 dd->ipath_f_tidtemplate = ipath_pe_tidtemplate;
+5 -5
drivers/infiniband/hw/ipath/ipath_intr.c
··· 710 710 * linuxbios development work, and it may happen in 711 711 * the future again. 712 712 */ 713 - if (dd->pcidev && dd->pcidev->irq) { 713 + if (dd->pcidev && dd->ipath_irq) { 714 714 ipath_dev_err(dd, "Now %u unexpected " 715 715 "interrupts, unregistering " 716 716 "interrupt handler\n", 717 717 *unexpectp); 718 - ipath_dbg("free_irq of irq %x\n", 719 - dd->pcidev->irq); 720 - free_irq(dd->pcidev->irq, dd); 718 + ipath_dbg("free_irq of irq %d\n", 719 + dd->ipath_irq); 720 + dd->ipath_f_free_irq(dd); 721 721 } 722 722 } 723 723 if (ipath_read_kreg32(dd, dd->ipath_kregs->kr_intmask)) { ··· 753 753 if (allbits == 2) { 754 754 ipath_dev_err(dd, "Still bad interrupt status, " 755 755 "unregistering interrupt\n"); 756 - free_irq(dd->pcidev->irq, dd); 756 + dd->ipath_f_free_irq(dd); 757 757 } else if (allbits > 2) { 758 758 if ((allbits % 10000) == 0) 759 759 printk(".");
+4
drivers/infiniband/hw/ipath/ipath_kernel.h
··· 213 213 void (*ipath_f_setextled)(struct ipath_devdata *, u64, u64); 214 214 /* fill out chip-specific fields */ 215 215 int (*ipath_f_get_base_info)(struct ipath_portdata *, void *); 216 + /* free irq */ 217 + void (*ipath_f_free_irq)(struct ipath_devdata *); 216 218 struct ipath_ibdev *verbs_dev; 217 219 struct timer_list verbs_timer; 218 220 /* total dwords sent (summed from counter) */ ··· 330 328 /* so we can rewrite it after a chip reset */ 331 329 u32 ipath_pcibar1; 332 330 331 + /* interrupt number */ 332 + int ipath_irq; 333 333 /* HT/PCI Vendor ID (here for NodeInfo) */ 334 334 u16 ipath_vendorid; 335 335 /* HT/PCI Device ID (here for NodeInfo) */