/** * hub_pio_map - establish a HUB PIO mapping * * @hub: hub to perform PIO mapping on * @widget: widget ID to perform PIO mapping for * @xtalk_addr: xtalk_address that needs to be mapped * @size: size of the PIO mapping * **/ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, unsigned long xtalk_addr, size_t size) { nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); volatile hubreg_t junk; unsigned i; /* use small-window mapping if possible */ if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE) return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE); if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) { printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx" " too big (%ld)\n", nasid, widget, xtalk_addr, size); return 0; } xtalk_addr &= ~(BWIN_SIZE-1); for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) { if (test_and_set_bit(i, hub_data(cnode)->h_bigwin_used)) continue; /* * The code below does a PIO write to setup an ITTE entry. * * We need to prevent other CPUs from seeing our updated * memory shadow of the ITTE (in the piomap) until the ITTE * entry is actually set up; otherwise, another CPU might * attempt a PIO prematurely. * * Also, the only way we can know that an entry has been * received by the hub and can be used by future PIO reads/ * writes is by reading back the ITTE entry after writing it. * * For these two reasons, we PIO read back the ITTE entry * after we write it. */ IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); junk = HUB_L(IIO_ITTE_GET(nasid, i)); return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE); } printk(KERN_WARNING "unable to establish PIO mapping for at" " hub %d widget %d addr 0x%lx\n", nasid, widget, xtalk_addr); return 0; }
/* ARGSUSED */ hub_piomap_t hub_piomap_alloc(devfs_handle_t dev, /* set up mapping for this device */ device_desc_t dev_desc, /* device descriptor */ iopaddr_t xtalk_addr, /* map for this xtalk_addr range */ size_t byte_count, size_t byte_count_max, /* maximum size of a mapping */ unsigned flags) /* defined in sys/pio.h */ { xwidget_info_t widget_info = xwidget_info_get(dev); xwidgetnum_t widget = xwidget_info_id_get(widget_info); devfs_handle_t hubv = xwidget_info_master_get(widget_info); hubinfo_t hubinfo; hub_piomap_t bw_piomap; int bigwin, free_bw_index; nasid_t nasid; volatile hubreg_t junk; int s; /* sanity check */ if (byte_count_max > byte_count) return(NULL); hubinfo_get(hubv, &hubinfo); /* If xtalk_addr range is mapped by a small window, we don't have * to do much */ if (xtalk_addr + byte_count <= SWIN_SIZE) return(hubinfo_swin_piomap_get(hubinfo, (int)widget)); /* We need to use a big window mapping. */ /* * TBD: Allow requests that would consume multiple big windows -- * split the request up and use multiple mapping entries. * For now, reject requests that span big windows. */ if ((xtalk_addr % BWIN_SIZE) + byte_count > BWIN_SIZE) return(NULL); /* Round xtalk address down for big window alignement */ xtalk_addr = xtalk_addr & ~(BWIN_SIZE-1); /* * Check to see if an existing big window mapping will suffice. */ tryagain: free_bw_index = -1; s = mutex_spinlock(&hubinfo->h_bwlock); for (bigwin=0; bigwin < HUB_NUM_BIG_WINDOW; bigwin++) { bw_piomap = hubinfo_bwin_piomap_get(hubinfo, bigwin); /* If mapping is not valid, skip it */ if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_VALID)) { free_bw_index = bigwin; continue; } /* * If mapping is UNFIXED, skip it. We don't allow sharing * of UNFIXED mappings, because this would allow starvation. */ if (!(bw_piomap->hpio_flags & HUB_PIOMAP_IS_FIXED)) continue; if ( xtalk_addr == bw_piomap->hpio_xtalk_info.xp_xtalk_addr && widget == bw_piomap->hpio_xtalk_info.xp_target) { bw_piomap->hpio_holdcnt++; mutex_spinunlock(&hubinfo->h_bwlock, s); return(bw_piomap); } } /* * None of the existing big window mappings will work for us -- * we need to establish a new mapping. */ /* Insure that we don't consume all big windows with FIXED mappings */ if (flags & PIOMAP_FIXED) { if (hubinfo->h_num_big_window_fixed < HUB_NUM_BIG_WINDOW-1) { ASSERT(free_bw_index >= 0); hubinfo->h_num_big_window_fixed++; } else { bw_piomap = NULL; goto done; } } else { /* PIOMAP_UNFIXED */ if (free_bw_index < 0) { if (flags & PIOMAP_NOSLEEP) { bw_piomap = NULL; goto done; } sv_wait(&hubinfo->h_bwwait, PZERO, &hubinfo->h_bwlock, s); goto tryagain; } } /* OK! Allocate big window free_bw_index for this mapping. */ /* * The code below does a PIO write to setup an ITTE entry. * We need to prevent other CPUs from seeing our updated memory * shadow of the ITTE (in the piomap) until the ITTE entry is * actually set up; otherwise, another CPU might attempt a PIO * prematurely. * * Also, the only way we can know that an entry has been received * by the hub and can be used by future PIO reads/writes is by * reading back the ITTE entry after writing it. * * For these two reasons, we PIO read back the ITTE entry after * we write it. */ nasid = hubinfo->h_nasid; IIO_ITTE_PUT(nasid, free_bw_index, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr); junk = HUB_L(IIO_ITTE_GET(nasid, free_bw_index)); bw_piomap = hubinfo_bwin_piomap_get(hubinfo, free_bw_index); bw_piomap->hpio_xtalk_info.xp_dev = dev; bw_piomap->hpio_xtalk_info.xp_target = widget; bw_piomap->hpio_xtalk_info.xp_xtalk_addr = xtalk_addr; bw_piomap->hpio_xtalk_info.xp_kvaddr = (caddr_t)NODE_BWIN_BASE(nasid, free_bw_index); bw_piomap->hpio_holdcnt++; bw_piomap->hpio_bigwin_num = free_bw_index; if (flags & PIOMAP_FIXED) bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID | HUB_PIOMAP_IS_FIXED; else bw_piomap->hpio_flags |= HUB_PIOMAP_IS_VALID; done: mutex_spinunlock(&hubinfo->h_bwlock, s); return(bw_piomap); }