Ejemplo n.º 1
0
cpuid_t
intr_heuristic(vertex_hdl_t dev,
               device_desc_t dev_desc,
               int	req_bit,
               int resflags,
               vertex_hdl_t owner_dev,
               char *name,
               int *resp_bit)
{
    cpuid_t		cpuid;
    cpuid_t		candidate = CPU_NONE;
    cnodeid_t	candidate_node;
    vertex_hdl_t	pconn_vhdl;
    pcibr_soft_t	pcibr_soft;
    int 		bit;
    static cnodeid_t last_node = 0;

    /* SN2 + pcibr addressing limitation */
    /* Due to this limitation, all interrupts from a given bridge must go to the name node.*/
    /* The interrupt must also be targetted for the same processor. */
    /* This limitation does not exist on PIC. */
    /* But, the processor limitation will stay.  The limitation will be similar to */
    /* the bedrock/xbridge limit regarding PI's */

    if ( (hwgraph_edge_get(dev, EDGE_LBL_PCI, &pconn_vhdl) == GRAPH_SUCCESS) &&
            ( (pcibr_soft = pcibr_soft_get(pconn_vhdl) ) != NULL) ) {
        if (pcibr_soft->bsi_err_intr) {
            candidate =  ((hub_intr_t)pcibr_soft->bsi_err_intr)->i_cpuid;
        }
    }


    if (candidate != CPU_NONE) {
        // The cpu was chosen already when we assigned the error interrupt.
        bit = intr_reserve_level(candidate,
                                 req_bit,
                                 resflags,
                                 owner_dev,
                                 name);
        if (bit < 0) {
            cpuid = CPU_NONE;
        } else {
            cpuid = candidate;
            *resp_bit = bit;
        }
    } else {
        // Need to choose one.  Try the controlling c-brick first.
        cpuid = intr_bit_reserve_test(CPU_NONE,
                                      0,
                                      master_node_get(dev),
                                      req_bit,
                                      0,
                                      owner_dev,
                                      name,
                                      resp_bit);
    }

    if (cpuid != CPU_NONE) {
        return cpuid;
    }

    if (candidate  != CPU_NONE) {
        printk("Cannot target interrupt to target node (%ld).\n",candidate);
        return CPU_NONE;
    } else {
        printk("Cannot target interrupt to closest node (0x%x) 0x%p\n",
               master_node_get(dev), (void *)owner_dev);
    }

    // We couldn't put it on the closest node.  Try to find another one.
    // Do a stupid round-robin assignment of the node.

    {
        int i;

        if (last_node >= numnodes) last_node = 0;
        for (i = 0, candidate_node = last_node; i < numnodes; candidate_node++,i++) {
            if (candidate_node == numnodes) candidate_node = 0;
            cpuid = intr_bit_reserve_test(CPU_NONE,
                                          0,
                                          candidate_node,
                                          req_bit,
                                          0,
                                          owner_dev,
                                          name,
                                          resp_bit);
            if (cpuid != CPU_NONE) {
                last_node = candidate_node + 1;
                return cpuid;
            }
        }
    }

    printk("cannot target interrupt: 0x%p\n",(void *)owner_dev);
    return CPU_NONE;
}
Ejemplo n.º 2
0
/*
 * Allocate resources required for an interrupt as specified in dev_desc.
 * Returns a hub interrupt handle on success, or 0 on failure.
 */
static hub_intr_t
do_hub_intr_alloc(devfs_handle_t dev,		/* which crosstalk device */
		  device_desc_t dev_desc,	/* device descriptor */
		  devfs_handle_t owner_dev,	/* owner of this interrupt, if known */
		  int uncond_nothread)		/* unconditionally non-threaded */
{
	cpuid_t cpu = (cpuid_t)0;			/* cpu to receive interrupt */
        int cpupicked = 0;
	int bit;			/* interrupt vector */
	/*REFERENCED*/
	int intr_resflags = 0;
	hub_intr_t intr_hdl;
	cnodeid_t nodeid;		/* node to receive interrupt */
	/*REFERENCED*/
	nasid_t nasid;			/* nasid to receive interrupt */
	struct xtalk_intr_s *xtalk_info;
	iopaddr_t xtalk_addr;		/* xtalk addr on hub to set intr */
	xwidget_info_t xwidget_info;	/* standard crosstalk widget info handle */
	char *intr_name = NULL;
	ilvl_t intr_swlevel = (ilvl_t)0;
	extern int default_intr_pri;
	extern void synergy_intr_alloc(int, int);


	if (dev_desc) {
		if (dev_desc->flags & D_INTR_ISERR) {
			intr_resflags = II_ERRORINT;
		} else if (!uncond_nothread && !(dev_desc->flags & D_INTR_NOTHREAD)) {
			intr_resflags = II_THREADED;
		} else {
			/* Neither an error nor a thread. */
			intr_resflags = 0;
		}
	} else {
		intr_swlevel = default_intr_pri;
		if (!uncond_nothread)
			intr_resflags = II_THREADED;
	}

	/* XXX - Need to determine if the interrupt should be threaded. */

	/* If the cpu has not been picked already then choose a candidate 
	 * interrupt target and reserve the interrupt bit 
	 */
	if (!cpupicked) {
		cpu = intr_heuristic(dev,dev_desc,allocate_my_bit,
				     intr_resflags,owner_dev,
				     intr_name,&bit);
	}

	/* At this point we SHOULD have a valid cpu */
	if (cpu == CPU_NONE) {
#if defined(SUPPORT_PRINTING_V_FORMAT)
		printk(KERN_WARNING  "%v hub_intr_alloc could not allocate interrupt\n",
			owner_dev);
#else
		printk(KERN_WARNING  "%p hub_intr_alloc could not allocate interrupt\n",
			(void *)owner_dev);
#endif
		return(0);

	}

	/* If the cpu has been picked already (due to the bridge data 
	 * corruption bug) then try to reserve an interrupt bit .
	 */
	if (cpupicked) {
		bit = intr_reserve_level(cpu, allocate_my_bit, 
					 intr_resflags, 
					 owner_dev, intr_name);
		if (bit < 0) {
#if defined(SUPPORT_PRINTING_V_FORMAT)
			printk(KERN_WARNING  "Could not reserve an interrupt bit for cpu "
				" %d and dev %v\n",
				cpu,owner_dev);
#else
			printk(KERN_WARNING  "Could not reserve an interrupt bit for cpu "
				" %d and dev %p\n",
				(int)cpu, (void *)owner_dev);
#endif
				
			return(0);
		}
	}

	nodeid = cpuid_to_cnodeid(cpu);
	nasid = cpuid_to_nasid(cpu);
	xtalk_addr = HUBREG_AS_XTALKADDR(nasid, PIREG(PI_INT_PEND_MOD, cpuid_to_subnode(cpu)));

	/*
	 * Allocate an interrupt handle, and fill it in.  There are two
	 * pieces to an interrupt handle: the piece needed by generic
	 * xtalk code which is used by crosstalk device drivers, and
	 * the piece needed by low-level IP27 hardware code.
	 */
	intr_hdl = snia_kmem_alloc_node(sizeof(struct hub_intr_s), KM_NOSLEEP, nodeid);
	ASSERT_ALWAYS(intr_hdl);

	/* 
	 * Fill in xtalk information for generic xtalk interfaces that
	 * operate on xtalk_intr_hdl's.
	 */
	xtalk_info = &intr_hdl->i_xtalk_info;
	xtalk_info->xi_dev = dev;
	xtalk_info->xi_vector = bit;
	xtalk_info->xi_addr = xtalk_addr;

	/*
	 * Regardless of which CPU we ultimately interrupt, a given crosstalk
	 * widget always handles interrupts (and PIO and DMA) through its 
	 * designated "master" crosstalk provider.
	 */
	xwidget_info = xwidget_info_get(dev);
	if (xwidget_info)
		xtalk_info->xi_target = xwidget_info_masterid_get(xwidget_info);

	/* Fill in low level hub information for hub_* interrupt interface */
	intr_hdl->i_swlevel = intr_swlevel;
	intr_hdl->i_cpuid = cpu;
	intr_hdl->i_bit = bit;
	intr_hdl->i_flags = HUB_INTR_IS_ALLOCED;

	/* Store the actual interrupt priority level & interrupt target
	 * cpu back in the device descriptor.
	 */
	hub_device_desc_update(dev_desc, intr_swlevel, cpu);
	synergy_intr_alloc((int)bit, (int)cpu);
	return(intr_hdl);
}