coherent hypertransport hardcodes.

Stefan Reinauer stepan at suse.de
Fri Jul 25 09:45:01 CEST 2003


* YhLu <YhLu at tyan.com> [030719 02:59]:

> I have tested Stefan's the code about coherent_ht.c, and add some hardcode
> to it.
> coherent_ht.o.c is the original one. Coherent_ht.1.c is total hardcode one.
> coherent_ht.c and coherent_ht.2.c are modified with some hardcode ones.
 
I am not happy with these hardcodes at all, they will make all
motherboards fail that have a different link setup than the tyan S2880
(It should be ok for hdama, but will definitely make the AMD quartet
fail)

Link speed and width setup should be done "dynamically" based on the link
capabilities of the devices connected to each other.

I wrote two functions to do this for every pair of hypertransport
devices, they should probably be enhanced to take a configurable
(per nvram or config option) maximum in addition to relying on what the
devices say.

This needs support from the motherboard specific Config.lb files,
because we need to know for every cpu which bridge/cpu is connected to 
which link on the hypertransport bus.

Tom from LNXI has also written some code that fills the speed registers
it seems. But this is executed in C-Payload when doing PCI. As we need
to assert LDTSTOP_L I am not sure whether it can be kept there. Tom?  

I checked in cpu and southbridge dependent parts of LDTSTOP_L assertion,
they should be operational as soon as we know the link configuration
from the config file .

The static tree generated at the moment seems not right to me:
for the one cpu that is actually configured, several nodes are
generated:

struct chip static_dev9 = {
/* cpu /home/stepan/LinuxBIOS/freebios2/src/cpu/k8 */
  .next = &static_dev8,
};
struct chip static_dev8 = {
/* cpu /home/stepan/LinuxBIOS/freebios2/src/cpu/k7 */
  .next = &static_dev7,
};
struct chip static_dev7 = {
/* cpu /home/stepan/LinuxBIOS/freebios2/src/cpu/p6 */
  .next = &static_dev6,
};
struct chip static_dev6 = {
/* cpu /home/stepan/LinuxBIOS/freebios2/src/cpu/p5 */
  .next = &static_dev5,
};

I assume this is to allow callbacks for each cpu type the k8
"implements" at the right place. but it looks really nasty. And
it seems that there are no callbacks anyways here. Or am I wrong?

Is this really needed? It looks like this should be one entry for every
cpu that can be plugged into the system, plus for every bridge on the
system.

In the config file this shows up as:

 option i686=1
 option i586=1
 option INTEL_PPRO_MTRR=1
 option k7=1
 option k8=1


Ron, is it already possible to add information on links between the
cht and ncht devices?

The chain i want to describe looks pretty much like:

       K8-CPU[2] ------- K8-CPU[3]
          |                 |
          |                 |
       K8-CPU[0] ------- K8-CPU[1]
          |                 |
          |                 |
       8111-SB[0]        8131-SB[0]

with possibly multiple bridges of the same type.


Stefan

-------------- next part --------------
#define SPEED_100  15
#define SPEED_200  0
#define SPEED_400  2
#define SPEED_600  4
#define SPEED_800  5
#define SPEED_1000 6
#define SUPPORTS(x) & (1<<x)

uint8_t get_maximum_cht_speed(uint16_t mask)
{
	if(mask SUPPORTS(SPEED_1000))
		return SPEED_1000;
	if(mask SUPPORTS(SPEED_800))
		return SPEED_800;
	if(mask SUPPORTS(SPEED_600))
		return SPEED_600;
	if(mask SUPPORTS(SPEED_400))
		return SPEED_400;
	if(mask SUPPORTS(SPEED_200))
		return SPEED_200;
	if(mask SUPPORTS(SPEED_100))
		return SPEED_100;
}

#if 1
void print_speed(uint8_t speed)
{
	const static char *speeds[]={ "200", "n/a", "400", "n/a", "600", "800", 
				     "1000", "n/a", "n/a", "n/a", "n/a", "n/a",
				     "n/a", "n/a", "n/a", "100" };
	print_debug("Link speed: ");
	print_debug(speeds[speed]);
	print_debug("MHz\r\n");

}
#endif

/*
 * dev_a, dev_b   :   device that share a link
 * link_a, link_b :   link output on device a/b (0,1,2)
 */

void setup_cht_linkspeed(device_t dev_a, device_t dev_b, 
				uint8_t link_a, uint8_t link_b)
{
	uint8_t reg_a, reg_b, speed_max;
	uint16_t speed_mask
	uint32_t tmp;

	reg_a = (0x20*link_a)+0x88;
	reg_b = (0x20*link_b)+0x88;

	/* 
	 * get link speed mask of both devices and AND them
	 * to get the speeds supported by both devices.
	 */

	speed_mask = (pci_read_config32(dev_a, reg_a) >> 16) & \
	               (pci_read_config32(dev_b, reg_b) >> 16);
	
	speed_max=get_maximum_cht_speed(speed_mask);
	
#if 1
	print_speed(speed_max);
#endif

	/* write link width on device a */
	tmp =  pci_read_config32(dev_a, reg_a);
	tmp &= ~(15<<8);
	tmp |= (speed_max<<8);
	pci_write_config32(dev_a, reg_a, tmp);
	
	/* write link width on device b */
	tmp =  pci_read_config32(dev_b, reg_b);
	tmp &= ~(15<<8);
	tmp |= (speed_max<<8);
	pci_write_config32(dev_b, reg_b, tmp);

}	
	


-------------- next part --------------

/*
 * dev_a, dev_b   :   device that share a link
 * link_a, link_b :   link output on device a/b (0,1,2)
 */

#if 1
int print_width(uint8_t width)
{
	switch (max_width) {
	case 0:
		print_debug("8bit");
		break;
	case 1:
		print_debug("16bit");	
		break;
	case 3:
		print_debug("32bit");
		break;
	case 4:
		print_debug("2bit");
		break;
	case 5:
		print_debug("4bit");
		break;
	case 7:
		print_debug("physically not connected");
		break;
	default:
		print_debug("unknown");
	}
}
#endif

void setup_cht_linkwidth(device_t dev_a, device_t dev_b, 
				uint8_t link_a, uint8_t link_b)
{
	uint8_t in_width, out_width, reg_a, reg_b;
	uint32_t tmp;

	reg_a = (0x20*link_a)+0x84;
	reg_b = (0x20*link_b)+0x84;

	/* get maximum link width in/out */
	in_width = ((pci_read_config32(dev_a, reg_a) >> 16) & 0x07) & \
	               ((pci_read_config32(dev_b, reg_b) >> 20) & 0x07);

	/* get maximum link width out/in */
	out_width = ((pci_read_config32(dev_a, reg_a) >> 20) & 0x07) & \
	               ((pci_read_config32(dev_b, reg_b) >> 16) & 0x07);

#if 1
	print_debug("link width ( a->b / b->a ) : ");
	print_width(in_width);
	print_debug("/");
	print_width(out_width);
	print_debug("\r\n");
#endif

	/* write link width on device a */
	tmp =  pci_read_config32(dev_a, reg_a);
	tmp &= ~( (7<<24) | (7<<28) );
	tmp |= ( (in_width<<24)|(out_width<<28) );
	pci_write_config32(dev_a, reg_a, tmp);
	
	/* write link width on device b */
	tmp =  pci_read_config32(dev_b, reg_b);
	tmp &= ~( (7<<24) | (7<<28) );
	tmp |= ( (out_width<<24)|(in_width<<28) );
	pci_write_config32(dev_b, reg_b, tmp);

}	
	




More information about the coreboot mailing list