--- zzzz-none-000/linux-3.10.107/drivers/vme/bridges/vme_tsi148.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/vme/bridges/vme_tsi148.c 2021-02-04 17:41:59.000000000 +0000 @@ -45,7 +45,7 @@ static const char driver_name[] = "vme_tsi148"; -static DEFINE_PCI_DEVICE_TABLE(tsi148_ids) = { +static const struct pci_device_id tsi148_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_TUNDRA, PCI_DEVICE_ID_TUNDRA_TSI148) }, { }, }; @@ -169,7 +169,7 @@ unsigned int error_addr_high, error_addr_low; unsigned long long error_addr; u32 error_attrib; - struct vme_bus_error *error; + int error_am; struct tsi148_driver *bridge; bridge = tsi148_bridge->driver_priv; @@ -177,6 +177,7 @@ error_addr_high = ioread32be(bridge->base + TSI148_LCSR_VEAU); error_addr_low = ioread32be(bridge->base + TSI148_LCSR_VEAL); error_attrib = ioread32be(bridge->base + TSI148_LCSR_VEAT); + error_am = (error_attrib & TSI148_LCSR_VEAT_AM_M) >> 8; reg_join(error_addr_high, error_addr_low, &error_addr); @@ -186,17 +187,12 @@ "Occurred\n"); } - error = kmalloc(sizeof(struct vme_bus_error), GFP_ATOMIC); - if (error) { - error->address = error_addr; - error->attributes = error_attrib; - list_add_tail(&error->list, &tsi148_bridge->vme_errors); - } else { - dev_err(tsi148_bridge->parent, "Unable to alloc memory for " - "VMEbus Error reporting\n"); - dev_err(tsi148_bridge->parent, "VME Bus Error at address: " - "0x%llx, attributes: %08x\n", error_addr, error_attrib); - } + if (err_chk) + vme_bus_error_handler(tsi148_bridge, error_addr, error_am); + else + dev_err(tsi148_bridge->parent, + "VME Bus Error at address: 0x%llx, attributes: %08x\n", + error_addr, error_attrib); /* Clear Status */ iowrite32be(TSI148_LCSR_VEAT_VESCL, bridge->base + TSI148_LCSR_VEAT); @@ -314,12 +310,11 @@ struct pci_dev *pdev; struct tsi148_driver *bridge; - pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev); + pdev = to_pci_dev(tsi148_bridge->parent); bridge = tsi148_bridge->driver_priv; - /* Initialise list for VME bus errors */ - INIT_LIST_HEAD(&tsi148_bridge->vme_errors); + INIT_LIST_HEAD(&tsi148_bridge->vme_error_handlers); mutex_init(&tsi148_bridge->irq_mtx); @@ -427,9 +422,7 @@ iowrite32be(tmp, bridge->base + TSI148_LCSR_INTEO); if (sync != 0) { - pdev = container_of(tsi148_bridge->parent, - struct pci_dev, dev); - + pdev = to_pci_dev(tsi148_bridge->parent); synchronize_irq(pdev->irq); } } else { @@ -479,73 +472,6 @@ } /* - * Find the first error in this address range - */ -static struct vme_bus_error *tsi148_find_error(struct vme_bridge *tsi148_bridge, - u32 aspace, unsigned long long address, size_t count) -{ - struct list_head *err_pos; - struct vme_bus_error *vme_err, *valid = NULL; - unsigned long long bound; - - bound = address + count; - - /* - * XXX We are currently not looking at the address space when parsing - * for errors. This is because parsing the Address Modifier Codes - * is going to be quite resource intensive to do properly. We - * should be OK just looking at the addresses and this is certainly - * much better than what we had before. - */ - err_pos = NULL; - /* Iterate through errors */ - list_for_each(err_pos, &tsi148_bridge->vme_errors) { - vme_err = list_entry(err_pos, struct vme_bus_error, list); - if ((vme_err->address >= address) && - (vme_err->address < bound)) { - - valid = vme_err; - break; - } - } - - return valid; -} - -/* - * Clear errors in the provided address range. - */ -static void tsi148_clear_errors(struct vme_bridge *tsi148_bridge, - u32 aspace, unsigned long long address, size_t count) -{ - struct list_head *err_pos, *temp; - struct vme_bus_error *vme_err; - unsigned long long bound; - - bound = address + count; - - /* - * XXX We are currently not looking at the address space when parsing - * for errors. This is because parsing the Address Modifier Codes - * is going to be quite resource intensive to do properly. We - * should be OK just looking at the addresses and this is certainly - * much better than what we had before. - */ - err_pos = NULL; - /* Iterate through errors */ - list_for_each_safe(err_pos, temp, &tsi148_bridge->vme_errors) { - vme_err = list_entry(err_pos, struct vme_bus_error, list); - - if ((vme_err->address >= address) && - (vme_err->address < bound)) { - - list_del(err_pos); - kfree(vme_err); - } - } -} - -/* * Initialize a slave window with the requested attributes. */ static int tsi148_slave_set(struct vme_slave_resource *image, int enabled, @@ -583,11 +509,6 @@ granularity = 0x10000; addr |= TSI148_LCSR_ITAT_AS_A64; break; - case VME_CRCSR: - case VME_USER1: - case VME_USER2: - case VME_USER3: - case VME_USER4: default: dev_err(tsi148_bridge->parent, "Invalid address space\n"); return -EINVAL; @@ -735,7 +656,7 @@ reg_join(vme_bound_high, vme_bound_low, &vme_bound); reg_join(pci_offset_high, pci_offset_low, &pci_offset); - *pci_base = (dma_addr_t)vme_base + pci_offset; + *pci_base = (dma_addr_t)(*vme_base + pci_offset); *enabled = 0; *aspace = 0; @@ -808,7 +729,7 @@ tsi148_bridge = image->parent; - pdev = container_of(tsi148_bridge->parent, struct pci_dev, dev); + pdev = to_pci_dev(tsi148_bridge->parent); existing_size = (unsigned long long)(image->bus_resource.end - image->bus_resource.start); @@ -847,7 +768,7 @@ image->bus_resource.flags = IORESOURCE_MEM; retval = pci_bus_alloc_resource(pdev->bus, - &image->bus_resource, size, size, PCIBIOS_MIN_MEM, + &image->bus_resource, size, 0x10000, PCIBIOS_MIN_MEM, 0, NULL, NULL); if (retval) { dev_err(tsi148_bridge->parent, "Failed to allocate mem " @@ -904,11 +825,15 @@ unsigned long long pci_bound, vme_offset, pci_base; struct vme_bridge *tsi148_bridge; struct tsi148_driver *bridge; + struct pci_bus_region region; + struct pci_dev *pdev; tsi148_bridge = image->parent; bridge = tsi148_bridge->driver_priv; + pdev = to_pci_dev(tsi148_bridge->parent); + /* Verify input data */ if (vme_base & 0xFFFF) { dev_err(tsi148_bridge->parent, "Invalid VME Window " @@ -943,7 +868,9 @@ pci_bound = 0; vme_offset = 0; } else { - pci_base = (unsigned long long)image->bus_resource.start; + pcibios_resource_to_bus(pdev->bus, ®ion, + &image->bus_resource); + pci_base = region.start; /* * Bound address is a valid address for the window, adjust @@ -1259,9 +1186,9 @@ int retval, enabled; unsigned long long vme_base, size; u32 aspace, cycle, dwidth; - struct vme_bus_error *vme_err = NULL; + struct vme_error_handler *handler = NULL; struct vme_bridge *tsi148_bridge; - void *addr = image->kern_base + offset; + void __iomem *addr = image->kern_base + offset; unsigned int done = 0; unsigned int count32; @@ -1269,9 +1196,20 @@ spin_lock(&image->lock); + if (err_chk) { + __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, + &cycle, &dwidth); + handler = vme_register_error_handler(tsi148_bridge, aspace, + vme_base + offset, count); + if (!handler) { + spin_unlock(&image->lock); + return -ENOMEM; + } + } + /* The following code handles VME address alignment. We cannot use - * memcpy_xxx directly here because it may cut small data transfers in - * to 8-bit cycles, thus making D16 cycle impossible. + * memcpy_xxx here because it may cut data transfers in to 8-bit + * cycles when D16 or D32 cycles are required on the VME bus. * On the other hand, the bridge itself assures that the maximum data * cycle configured for the transfer is used and splits it * automatically for non-aligned addresses, so we don't want the @@ -1295,9 +1233,9 @@ } count32 = (count - done) & ~0x3; - if (count32 > 0) { - memcpy_fromio(buf + done, addr + done, count32); - done += count32; + while (done < count32) { + *(u32 *)(buf + done) = ioread32(addr + done); + done += 4; } if ((count - done) & 0x2) { @@ -1312,24 +1250,16 @@ out: retval = count; - if (!err_chk) - goto skip_chk; - - __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle, - &dwidth); - - vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset, - count); - if (vme_err != NULL) { - dev_err(image->parent->parent, "First VME read error detected " - "an at address 0x%llx\n", vme_err->address); - retval = vme_err->address - (vme_base + offset); - /* Clear down save errors in this address range */ - tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset, - count); + if (err_chk) { + if (handler->num_errors) { + dev_err(image->parent->parent, + "First VME read error detected an at address 0x%llx\n", + handler->first_error); + retval = handler->first_error - (vme_base + offset); + } + vme_unregister_error_handler(handler); } -skip_chk: spin_unlock(&image->lock); return retval; @@ -1342,11 +1272,11 @@ int retval = 0, enabled; unsigned long long vme_base, size; u32 aspace, cycle, dwidth; - void *addr = image->kern_base + offset; + void __iomem *addr = image->kern_base + offset; unsigned int done = 0; unsigned int count32; - struct vme_bus_error *vme_err = NULL; + struct vme_error_handler *handler = NULL; struct vme_bridge *tsi148_bridge; struct tsi148_driver *bridge; @@ -1356,8 +1286,19 @@ spin_lock(&image->lock); + if (err_chk) { + __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, + &cycle, &dwidth); + handler = vme_register_error_handler(tsi148_bridge, aspace, + vme_base + offset, count); + if (!handler) { + spin_unlock(&image->lock); + return -ENOMEM; + } + } + /* Here we apply for the same strategy we do in master_read - * function in order to assure D16 cycle when required. + * function in order to assure the correct cycles. */ if ((uintptr_t)addr & 0x1) { iowrite8(*(u8 *)buf, addr); @@ -1377,9 +1318,9 @@ } count32 = (count - done) & ~0x3; - if (count32 > 0) { - memcpy_toio(addr + done, buf + done, count32); - done += count32; + while (done < count32) { + iowrite32(*(u32 *)(buf + done), addr + done); + done += 4; } if ((count - done) & 0x2) { @@ -1405,30 +1346,18 @@ * We check for saved errors in the written address range/space. */ - if (!err_chk) - goto skip_chk; - - /* - * Get window info first, to maximise the time that the buffers may - * fluch on their own - */ - __tsi148_master_get(image, &enabled, &vme_base, &size, &aspace, &cycle, - &dwidth); - - ioread16(bridge->flush_image->kern_base + 0x7F000); + if (err_chk) { + ioread16(bridge->flush_image->kern_base + 0x7F000); - vme_err = tsi148_find_error(tsi148_bridge, aspace, vme_base + offset, - count); - if (vme_err != NULL) { - dev_warn(tsi148_bridge->parent, "First VME write error detected" - " an at address 0x%llx\n", vme_err->address); - retval = vme_err->address - (vme_base + offset); - /* Clear down save errors in this address range */ - tsi148_clear_errors(tsi148_bridge, aspace, vme_base + offset, - count); + if (handler->num_errors) { + dev_warn(tsi148_bridge->parent, + "First VME write error detected an at address 0x%llx\n", + handler->first_error); + retval = handler->first_error - (vme_base + offset); + } + vme_unregister_error_handler(handler); } -skip_chk: spin_unlock(&image->lock); return retval; @@ -1828,24 +1757,29 @@ /* Add to list */ list_add_tail(&entry->list, &list->entries); + entry->dma_handle = dma_map_single(tsi148_bridge->parent, + &entry->descriptor, + sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE); + if (dma_mapping_error(tsi148_bridge->parent, entry->dma_handle)) { + dev_err(tsi148_bridge->parent, "DMA mapping error\n"); + retval = -EINVAL; + goto err_dma; + } + /* Fill out previous descriptors "Next Address" */ if (entry->list.prev != &list->entries) { - prev = list_entry(entry->list.prev, struct tsi148_dma_entry, - list); - /* We need the bus address for the pointer */ - entry->dma_handle = dma_map_single(tsi148_bridge->parent, - &entry->descriptor, - sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE); - reg_split((unsigned long long)entry->dma_handle, &address_high, &address_low); - entry->descriptor.dnlau = cpu_to_be32(address_high); - entry->descriptor.dnlal = cpu_to_be32(address_low); + prev = list_entry(entry->list.prev, struct tsi148_dma_entry, + list); + prev->descriptor.dnlau = cpu_to_be32(address_high); + prev->descriptor.dnlal = cpu_to_be32(address_low); } return 0; +err_dma: err_dest: err_source: err_align: @@ -1882,7 +1816,7 @@ static int tsi148_dma_list_exec(struct vme_dma_list *list) { struct vme_dma_resource *ctrlr; - int channel, retval = 0; + int channel, retval; struct tsi148_dma_entry *entry; u32 bus_addr_high, bus_addr_low; u32 val, dctlreg = 0; @@ -1916,10 +1850,6 @@ entry = list_first_entry(&list->entries, struct tsi148_dma_entry, list); - entry->dma_handle = dma_map_single(tsi148_bridge->parent, - &entry->descriptor, - sizeof(struct tsi148_dma_descriptor), DMA_TO_DEVICE); - mutex_unlock(&ctrlr->mtx); reg_split(entry->dma_handle, &bus_addr_high, &bus_addr_low); @@ -1936,9 +1866,19 @@ iowrite32be(dctlreg | TSI148_LCSR_DCTL_DGO, bridge->base + TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL); - wait_event_interruptible(bridge->dma_queue[channel], + retval = wait_event_interruptible(bridge->dma_queue[channel], tsi148_dma_busy(ctrlr->parent, channel)); + if (retval) { + iowrite32be(dctlreg | TSI148_LCSR_DCTL_ABT, bridge->base + + TSI148_LCSR_DMA[channel] + TSI148_LCSR_OFFSET_DCTL); + /* Wait for the operation to abort */ + wait_event(bridge->dma_queue[channel], + tsi148_dma_busy(ctrlr->parent, channel)); + retval = -EINTR; + goto exit; + } + /* * Read status register, this register is valid until we kick off a * new transfer. @@ -1951,6 +1891,7 @@ retval = -EIO; } +exit: /* Remove list from running list */ mutex_lock(&ctrlr->mtx); list_del(&list->list); @@ -2226,7 +2167,7 @@ struct pci_dev *pdev; /* Find pci_dev container of dev */ - pdev = container_of(parent, struct pci_dev, dev); + pdev = to_pci_dev(parent); return pci_alloc_consistent(pdev, size, dma); } @@ -2237,7 +2178,7 @@ struct pci_dev *pdev; /* Find pci_dev container of dev */ - pdev = container_of(parent, struct pci_dev, dev); + pdev = to_pci_dev(parent); pci_free_consistent(pdev, size, vaddr, dma); } @@ -2265,16 +2206,14 @@ bridge = tsi148_bridge->driver_priv; /* Allocate mem for CR/CSR image */ - bridge->crcsr_kernel = pci_alloc_consistent(pdev, VME_CRCSR_BUF_SIZE, - &bridge->crcsr_bus); + bridge->crcsr_kernel = pci_zalloc_consistent(pdev, VME_CRCSR_BUF_SIZE, + &bridge->crcsr_bus); if (bridge->crcsr_kernel == NULL) { dev_err(tsi148_bridge->parent, "Failed to allocate memory for " "CR/CSR image\n"); return -ENOMEM; } - memset(bridge->crcsr_kernel, 0, VME_CRCSR_BUF_SIZE); - reg_split(bridge->crcsr_bus, &crcsr_bus_high, &crcsr_bus_low); iowrite32be(crcsr_bus_high, bridge->base + TSI148_LCSR_CROU); @@ -2294,12 +2233,13 @@ dev_info(tsi148_bridge->parent, "CR/CSR Offset: %d\n", cbar); crat = ioread32be(bridge->base + TSI148_LCSR_CRAT); - if (crat & TSI148_LCSR_CRAT_EN) { + if (crat & TSI148_LCSR_CRAT_EN) + dev_info(tsi148_bridge->parent, "CR/CSR already enabled\n"); + else { dev_info(tsi148_bridge->parent, "Enabling CR/CSR space\n"); iowrite32be(crat | TSI148_LCSR_CRAT_EN, bridge->base + TSI148_LCSR_CRAT); - } else - dev_info(tsi148_bridge->parent, "CR/CSR already enabled\n"); + } /* If we want flushed, error-checked writes, set up a window * over the CR/CSR registers. We read from here to safely flush @@ -2441,13 +2381,6 @@ spin_lock_init(&tsi148_device->flush_image->lock); tsi148_device->flush_image->locked = 1; tsi148_device->flush_image->number = master_num; - tsi148_device->flush_image->address_attr = VME_A16 | VME_A24 | - VME_A32 | VME_A64; - tsi148_device->flush_image->cycle_attr = VME_SCT | VME_BLT | - VME_MBLT | VME_2eVME | VME_2eSST | VME_2eSSTB | - VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER | - VME_USER | VME_PROG | VME_DATA; - tsi148_device->flush_image->width_attr = VME_D16 | VME_D32; memset(&tsi148_device->flush_image->bus_resource, 0, sizeof(struct resource)); tsi148_device->flush_image->kern_base = NULL; @@ -2469,7 +2402,8 @@ master_image->locked = 0; master_image->number = i; master_image->address_attr = VME_A16 | VME_A24 | VME_A32 | - VME_A64; + VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 | + VME_USER3 | VME_USER4; master_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | @@ -2498,8 +2432,7 @@ slave_image->locked = 0; slave_image->number = i; slave_image->address_attr = VME_A16 | VME_A24 | VME_A32 | - VME_A64 | VME_CRCSR | VME_USER1 | VME_USER2 | - VME_USER3 | VME_USER4; + VME_A64; slave_image->cycle_attr = VME_SCT | VME_BLT | VME_MBLT | VME_2eVME | VME_2eSST | VME_2eSSTB | VME_2eSST160 | VME_2eSST267 | VME_2eSST320 | VME_SUPER | VME_USER | @@ -2582,7 +2515,8 @@ dev_info(&pdev->dev, "VME Write and flush and error check is %s\n", err_chk ? "enabled" : "disabled"); - if (tsi148_crcsr_init(tsi148_bridge, pdev)) { + retval = tsi148_crcsr_init(tsi148_bridge, pdev); + if (retval) { dev_err(&pdev->dev, "CR/CSR configuration failed.\n"); goto err_crcsr; }