From a65da0c3dac6e2d4f8ecf0aee8b0abe10001f2d9 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 21 Nov 2014 14:09:52 +0000 Subject: [PATCH 1/4] defxx: Fix DEFPA enable error propagation Correctly propagate the error code from `pci_enable_device' if non zero. Currently a failure of this function is correctly recognized and device initialization abandoned, however a successful completion code returned. Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index caed6eee289c..d8d4f3d3ca32 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -542,10 +542,13 @@ static int dfx_register(struct device *bdev) } /* Enable PCI device. */ - if (dfx_bus_pci && pci_enable_device(to_pci_dev(bdev))) { - printk(KERN_ERR "%s: Cannot enable PCI device, aborting\n", - print_name); - goto err_out; + if (dfx_bus_pci) { + err = pci_enable_device(to_pci_dev(bdev)); + if (err) { + pr_err("%s: Cannot enable PCI device, aborting\n", + print_name); + goto err_out; + } } SET_NETDEV_DEV(dev, bdev); From fef85fc466ec1f4400a902049a519948f6b40979 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 21 Nov 2014 14:09:57 +0000 Subject: [PATCH 2/4] defxx: Correct DEFEA's ESIC MMIO decoding Use ESIC's memory area 1 (MEMCS1) and its Memory Address High Compare and Memory Address Low Compare registers to set up the MMIO range for decoding accesses to PDQ ASIC registers. Previously the PDQ ASIC was thought to be addressable with the memory area 0 (MEMCS0) and its Memory Address Compare and Memory Address Mask registers. The MMIO range allocated for the option card is preset via ECU (EISA Configuration Utility) and can be disabled, so handle such a case gracefully too. Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 61 +++++++++++++++++++++++++--------------- drivers/net/fddi/defxx.h | 2 +- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index d8d4f3d3ca32..75d54ea72c56 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -447,23 +447,24 @@ static void dfx_get_bars(struct device *bdev, } if (dfx_bus_eisa) { unsigned long base_addr = to_eisa_device(bdev)->base_addr; - resource_size_t bar; + resource_size_t bar_lo; + resource_size_t bar_hi; if (dfx_use_mmio) { - bar = inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_2); - bar <<= 8; - bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_1); - bar <<= 8; - bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_CMP_0); - bar <<= 16; - *bar_start = bar; - bar = inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_2); - bar <<= 8; - bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_1); - bar <<= 8; - bar |= inb(base_addr + PI_ESIC_K_MEM_ADD_MASK_0); - bar <<= 16; - *bar_len = (bar | PI_MEM_ADD_MASK_M) + 1; + bar_lo = inb(base_addr + PI_ESIC_K_MEM_ADD_LO_CMP_2); + bar_lo <<= 8; + bar_lo |= inb(base_addr + PI_ESIC_K_MEM_ADD_LO_CMP_1); + bar_lo <<= 8; + bar_lo |= inb(base_addr + PI_ESIC_K_MEM_ADD_LO_CMP_0); + bar_lo <<= 8; + *bar_start = bar_lo; + bar_hi = inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_2); + bar_hi <<= 8; + bar_hi |= inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_1); + bar_hi <<= 8; + bar_hi |= inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_0); + bar_hi <<= 8; + *bar_len = ((bar_hi - bar_lo) | PI_MEM_ADD_MASK_M) + 1; } else { *bar_start = base_addr; *bar_len = PI_ESIC_K_CSR_IO_LEN + @@ -518,6 +519,7 @@ static int dfx_register(struct device *bdev) { static int version_disp; int dfx_bus_pci = dev_is_pci(bdev); + int dfx_bus_eisa = DFX_BUS_EISA(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; const char *print_name = dev_name(bdev); @@ -558,6 +560,16 @@ static int dfx_register(struct device *bdev) dev_set_drvdata(bdev, dev); dfx_get_bars(bdev, &bar_start, &bar_len); + if (dfx_bus_eisa && dfx_use_mmio && bar_start == 0) { + pr_err("%s: Cannot use MMIO, no address set, aborting\n", + print_name); + pr_err("%s: Run ECU and set adapter's MMIO location\n", + print_name); + pr_err("%s: Or recompile driver with \"CONFIG_DEFXX_MMIO=n\"" + "\n", print_name); + err = -ENXIO; + goto err_out; + } if (dfx_use_mmio) region = request_mem_region(bar_start, bar_len, print_name); @@ -714,13 +726,14 @@ static void dfx_bus_init(struct net_device *dev) } /* - * Enable memory decoding (MEMCS0) and/or port decoding + * Enable memory decoding (MEMCS1) and/or port decoding * (IOCS1/IOCS0) as appropriate in Function Control - * Register. IOCS0 is used for PDQ registers, taking 16 - * 32-bit words, while IOCS1 is used for the Burst Holdoff - * register, taking a single 32-bit word only. We use the - * slot-specific I/O range as per the ESIC spec, that is - * set bits 15:12 in the mask registers to mask them out. + * Register. MEMCS1 or IOCS0 is used for PDQ registers, + * taking 16 32-bit words, while IOCS1 is used for the + * Burst Holdoff register, taking a single 32-bit word + * only. We use the slot-specific I/O range as per the + * ESIC spec, that is set bits 15:12 in the mask registers + * to mask them out. */ /* Set the decode range of the board. */ @@ -745,9 +758,11 @@ static void dfx_bus_init(struct net_device *dev) outb(val, base_addr + PI_ESIC_K_IO_ADD_MASK_1_0); /* Enable the decoders. */ - val = PI_FUNCTION_CNTRL_M_IOCS1 | PI_FUNCTION_CNTRL_M_IOCS0; + val = PI_FUNCTION_CNTRL_M_IOCS1; if (dfx_use_mmio) - val |= PI_FUNCTION_CNTRL_M_MEMCS0; + val |= PI_FUNCTION_CNTRL_M_MEMCS1; + else + val |= PI_FUNCTION_CNTRL_M_IOCS0; outb(val, base_addr + PI_ESIC_K_FUNCTION_CNTRL); /* diff --git a/drivers/net/fddi/defxx.h b/drivers/net/fddi/defxx.h index 9527f0182fd4..16fe8049b238 100644 --- a/drivers/net/fddi/defxx.h +++ b/drivers/net/fddi/defxx.h @@ -1556,7 +1556,7 @@ typedef union #define PI_BURST_HOLDOFF_V_RESERVED 1 #define PI_BURST_HOLDOFF_V_MEM_MAP 0 -/* Define the implicit mask of the Memory Address Mask Register. */ +/* Define the implicit mask of the Memory Address Compare registers. */ #define PI_MEM_ADD_MASK_M 0x3ff From 6a931423c918633d4d0cda96df042d7e44ad06b0 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 21 Nov 2014 14:10:02 +0000 Subject: [PATCH 3/4] defxx: Disable DEFEA's ESIC I/O decoding on shutdown Make sure the option card does not respond after shutdown by disabling it via ESIC's Expansion Board Control register. Also disable memory and port I/O decoders, the latter in particular to disable slot-specific I/O decoding that otherwise remains active even in the board is disabled. Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index 75d54ea72c56..d057d9c2cf5e 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -856,6 +856,12 @@ static void dfx_bus_uninit(struct net_device *dev) val = inb(base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); val &= ~PI_CONFIG_STAT_0_M_INT_ENB; outb(val, base_addr + PI_ESIC_K_IO_CONFIG_STAT_0); + + /* Disable the board. */ + outb(0, base_addr + PI_ESIC_K_SLOT_CNTRL); + + /* Disable memory and port decoders. */ + outb(0, base_addr + PI_ESIC_K_FUNCTION_CNTRL); } if (dfx_bus_pci) { /* Disable interrupts at PCI bus interface chip (PFI) */ From 4d0438e56a8f9a1a18ba31bd53b9dc67af224980 Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Fri, 21 Nov 2014 14:10:08 +0000 Subject: [PATCH 4/4] defxx: Clean up DEFEA resource management Reserve DEFEA resources according to actual use. There are three regions, for the ESIC ASIC's CSRs, for the discrete Burst Holdoff register, and for the PDQ ASIC's CSRs. The latter is mapped in the memory or port I/O address space depending on configuration. The two formers are hardwired and always mapped in the port I/O address space. Signed-off-by: Maciej W. Rozycki Signed-off-by: David S. Miller --- drivers/net/fddi/defxx.c | 115 ++++++++++++++++++++++++++------------- drivers/net/fddi/defxx.h | 2 + 2 files changed, 80 insertions(+), 37 deletions(-) diff --git a/drivers/net/fddi/defxx.c b/drivers/net/fddi/defxx.c index d057d9c2cf5e..7f975a2c8990 100644 --- a/drivers/net/fddi/defxx.c +++ b/drivers/net/fddi/defxx.c @@ -414,7 +414,7 @@ static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) * ================ * * Overview: - * Retrieves the address range used to access control and status + * Retrieves the address ranges used to access control and status * registers. * * Returns: @@ -422,8 +422,8 @@ static void dfx_port_read_long(DFX_board_t *bp, int offset, u32 *data) * * Arguments: * bdev - pointer to device information - * bar_start - pointer to store the start address - * bar_len - pointer to store the length of the area + * bar_start - pointer to store the start addresses + * bar_len - pointer to store the lengths of the areas * * Assumptions: * I am sure there are some. @@ -442,8 +442,10 @@ static void dfx_get_bars(struct device *bdev, if (dfx_bus_pci) { int num = dfx_use_mmio ? 0 : 1; - *bar_start = pci_resource_start(to_pci_dev(bdev), num); - *bar_len = pci_resource_len(to_pci_dev(bdev), num); + bar_start[0] = pci_resource_start(to_pci_dev(bdev), num); + bar_len[0] = pci_resource_len(to_pci_dev(bdev), num); + bar_start[2] = bar_start[1] = 0; + bar_len[2] = bar_len[1] = 0; } if (dfx_bus_eisa) { unsigned long base_addr = to_eisa_device(bdev)->base_addr; @@ -457,24 +459,30 @@ static void dfx_get_bars(struct device *bdev, bar_lo <<= 8; bar_lo |= inb(base_addr + PI_ESIC_K_MEM_ADD_LO_CMP_0); bar_lo <<= 8; - *bar_start = bar_lo; + bar_start[0] = bar_lo; bar_hi = inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_2); bar_hi <<= 8; bar_hi |= inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_1); bar_hi <<= 8; bar_hi |= inb(base_addr + PI_ESIC_K_MEM_ADD_HI_CMP_0); bar_hi <<= 8; - *bar_len = ((bar_hi - bar_lo) | PI_MEM_ADD_MASK_M) + 1; + bar_len[0] = ((bar_hi - bar_lo) | PI_MEM_ADD_MASK_M) + + 1; } else { - *bar_start = base_addr; - *bar_len = PI_ESIC_K_CSR_IO_LEN + - PI_ESIC_K_BURST_HOLDOFF_LEN; + bar_start[0] = base_addr; + bar_len[0] = PI_ESIC_K_CSR_IO_LEN; } + bar_start[1] = base_addr + PI_DEFEA_K_BURST_HOLDOFF; + bar_len[1] = PI_ESIC_K_BURST_HOLDOFF_LEN; + bar_start[2] = base_addr + PI_ESIC_K_ESIC_CSR; + bar_len[2] = PI_ESIC_K_ESIC_CSR_LEN; } if (dfx_bus_tc) { - *bar_start = to_tc_dev(bdev)->resource.start + - PI_TC_K_CSR_OFFSET; - *bar_len = PI_TC_K_CSR_LEN; + bar_start[0] = to_tc_dev(bdev)->resource.start + + PI_TC_K_CSR_OFFSET; + bar_len[0] = PI_TC_K_CSR_LEN; + bar_start[2] = bar_start[1] = 0; + bar_len[2] = bar_len[1] = 0; } } @@ -525,8 +533,8 @@ static int dfx_register(struct device *bdev) const char *print_name = dev_name(bdev); struct net_device *dev; DFX_board_t *bp; /* board pointer */ - resource_size_t bar_start = 0; /* pointer to port */ - resource_size_t bar_len = 0; /* resource length */ + resource_size_t bar_start[3]; /* pointers to ports */ + resource_size_t bar_len[3]; /* resource length */ int alloc_size; /* total buffer size used */ struct resource *region; int err = 0; @@ -559,8 +567,8 @@ static int dfx_register(struct device *bdev) bp->bus_dev = bdev; dev_set_drvdata(bdev, dev); - dfx_get_bars(bdev, &bar_start, &bar_len); - if (dfx_bus_eisa && dfx_use_mmio && bar_start == 0) { + dfx_get_bars(bdev, bar_start, bar_len); + if (dfx_bus_eisa && dfx_use_mmio && bar_start[0] == 0) { pr_err("%s: Cannot use MMIO, no address set, aborting\n", print_name); pr_err("%s: Run ECU and set adapter's MMIO location\n", @@ -572,28 +580,49 @@ static int dfx_register(struct device *bdev) } if (dfx_use_mmio) - region = request_mem_region(bar_start, bar_len, print_name); + region = request_mem_region(bar_start[0], bar_len[0], + print_name); else - region = request_region(bar_start, bar_len, print_name); + region = request_region(bar_start[0], bar_len[0], print_name); if (!region) { - printk(KERN_ERR "%s: Cannot reserve I/O resource " - "0x%lx @ 0x%lx, aborting\n", - print_name, (long)bar_len, (long)bar_start); + pr_err("%s: Cannot reserve %s resource 0x%lx @ 0x%lx, " + "aborting\n", dfx_use_mmio ? "MMIO" : "I/O", print_name, + (long)bar_len[0], (long)bar_start[0]); err = -EBUSY; goto err_out_disable; } + if (bar_start[1] != 0) { + region = request_region(bar_start[1], bar_len[1], print_name); + if (!region) { + pr_err("%s: Cannot reserve I/O resource " + "0x%lx @ 0x%lx, aborting\n", print_name, + (long)bar_len[1], (long)bar_start[1]); + err = -EBUSY; + goto err_out_csr_region; + } + } + if (bar_start[2] != 0) { + region = request_region(bar_start[2], bar_len[2], print_name); + if (!region) { + pr_err("%s: Cannot reserve I/O resource " + "0x%lx @ 0x%lx, aborting\n", print_name, + (long)bar_len[2], (long)bar_start[2]); + err = -EBUSY; + goto err_out_bh_region; + } + } /* Set up I/O base address. */ if (dfx_use_mmio) { - bp->base.mem = ioremap_nocache(bar_start, bar_len); + bp->base.mem = ioremap_nocache(bar_start[0], bar_len[0]); if (!bp->base.mem) { printk(KERN_ERR "%s: Cannot map MMIO\n", print_name); err = -ENOMEM; - goto err_out_region; + goto err_out_esic_region; } } else { - bp->base.port = bar_start; - dev->base_addr = bar_start; + bp->base.port = bar_start[0]; + dev->base_addr = bar_start[0]; } /* Initialize new device structure */ @@ -602,7 +631,7 @@ static int dfx_register(struct device *bdev) if (dfx_bus_pci) pci_set_master(to_pci_dev(bdev)); - if (dfx_driver_init(dev, print_name, bar_start) != DFX_K_SUCCESS) { + if (dfx_driver_init(dev, print_name, bar_start[0]) != DFX_K_SUCCESS) { err = -ENODEV; goto err_out_unmap; } @@ -630,11 +659,19 @@ err_out_unmap: if (dfx_use_mmio) iounmap(bp->base.mem); -err_out_region: +err_out_esic_region: + if (bar_start[2] != 0) + release_region(bar_start[2], bar_len[2]); + +err_out_bh_region: + if (bar_start[1] != 0) + release_region(bar_start[1], bar_len[1]); + +err_out_csr_region: if (dfx_use_mmio) - release_mem_region(bar_start, bar_len); + release_mem_region(bar_start[0], bar_len[0]); else - release_region(bar_start, bar_len); + release_region(bar_start[0], bar_len[0]); err_out_disable: if (dfx_bus_pci) @@ -1085,8 +1122,8 @@ static int dfx_driver_init(struct net_device *dev, const char *print_name, board_name = "DEFEA"; if (dfx_bus_pci) board_name = "DEFPA"; - pr_info("%s: %s at %saddr = 0x%llx, IRQ = %d, Hardware addr = %pMF\n", - print_name, board_name, dfx_use_mmio ? "" : "I/O ", + pr_info("%s: %s at %s addr = 0x%llx, IRQ = %d, Hardware addr = %pMF\n", + print_name, board_name, dfx_use_mmio ? "MMIO" : "I/O", (long long)bar_start, dev->irq, dev->dev_addr); /* @@ -3660,8 +3697,8 @@ static void dfx_unregister(struct device *bdev) int dfx_bus_pci = dev_is_pci(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - resource_size_t bar_start = 0; /* pointer to port */ - resource_size_t bar_len = 0; /* resource length */ + resource_size_t bar_start[3]; /* pointers to ports */ + resource_size_t bar_len[3]; /* resource lengths */ int alloc_size; /* total buffer size used */ unregister_netdev(dev); @@ -3679,12 +3716,16 @@ static void dfx_unregister(struct device *bdev) dfx_bus_uninit(dev); - dfx_get_bars(bdev, &bar_start, &bar_len); + dfx_get_bars(bdev, bar_start, bar_len); + if (bar_start[2] != 0) + release_region(bar_start[2], bar_len[2]); + if (bar_start[1] != 0) + release_region(bar_start[1], bar_len[1]); if (dfx_use_mmio) { iounmap(bp->base.mem); - release_mem_region(bar_start, bar_len); + release_mem_region(bar_start[0], bar_len[0]); } else - release_region(bar_start, bar_len); + release_region(bar_start[0], bar_len[0]); if (dfx_bus_pci) pci_disable_device(to_pci_dev(bdev)); diff --git a/drivers/net/fddi/defxx.h b/drivers/net/fddi/defxx.h index 16fe8049b238..9d30fde2ef3c 100644 --- a/drivers/net/fddi/defxx.h +++ b/drivers/net/fddi/defxx.h @@ -1481,9 +1481,11 @@ typedef union #define PI_ESIC_K_CSR_IO_LEN 0x40 /* 64 bytes */ #define PI_ESIC_K_BURST_HOLDOFF_LEN 0x04 /* 4 bytes */ +#define PI_ESIC_K_ESIC_CSR_LEN 0x40 /* 64 bytes */ #define PI_DEFEA_K_CSR_IO 0x000 #define PI_DEFEA_K_BURST_HOLDOFF 0x040 +#define PI_ESIC_K_ESIC_CSR 0xC80 #define PI_ESIC_K_SLOT_ID 0xC80 #define PI_ESIC_K_SLOT_CNTRL 0xC84