[Nouveau] [PATCH] drm/nouveau: fix vbios load and check functions on PowerPC
Marcin Slusarz
marcin.slusarz at gmail.com
Wed Apr 14 05:44:50 PDT 2010
On Tue, Mar 23, 2010 at 06:09:07PM +0100, tacconet at libero.it wrote:
> From: Andrea Tacconi <tacconet at libero.it>
>
> Subject: [PATCH] drm/nouveau: fix vbios load and check functions on PowerPC
>
> On PowerPC the Bios signature reports a wrong lenght of video rom.
> Fix this by reading the correct size from Open Firmware.
>
> Set Pramin as primary vbios searching method, because it's the only working method on PowerPC.
>
> The nv_cksum function always fails.
> Fix this by Calculating and adding checksum byte at the end of vbios.
>
> Signed-off-by: Andrea Tacconi <tacconet at libero.it>
> ---
> diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
> index 6b6c303..c234b45 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_bios.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
> @@ -69,12 +69,29 @@ static bool nv_cksum(const uint8_t *data, unsigned int length)
> static int
> score_vbios(struct drm_device *dev, const uint8_t *data, const bool writeable)
> {
> + int bios_size = 0;
> +#if defined(__powerpc__)
> + struct device_node *dn = NULL;
> +#endif
> +
> if (!(data[0] == 0x55 && data[1] == 0xAA)) {
> NV_TRACEWARN(dev, "... BIOS signature not found\n");
> return 0;
> }
> +#if defined(__powerpc__)
> + /*
> + * The Bios signature reports a wrong lenght of rom.
> + * The correct size is read from Open Firmware.
> + */
> + dn = pci_device_to_OF_node(dev->pdev);
> + of_find_property(dn, "NVDA,BMP", &bios_size);
> + /* added checksum byte */
> + bios_size++;
> +#else
> + bios_size = (data[2] * 512);
> +#endif
>
> - if (nv_cksum(data, data[2] * 512)) {
> + if (nv_cksum(data, bios_size)) {
how about factoring bios_size calculation to another function?
#if defined(__powerpc__)
int fun()
{
}
#else
int fun()
{
}
#endif
> NV_TRACEWARN(dev, "... BIOS checksum invalid\n");
> /* if a ro image is somewhat bad, it's probably all rubbish */
> return writeable ? 2 : 1;
> @@ -183,11 +200,22 @@ struct methods {
> const bool rw;
> };
>
> +#if defined(__powerpc__)
> + /*
> + * For now PRAMIN is the only working method on PowerPC
> + */
> +static struct methods nv04_methods[] = {
> + { "PRAMIN", load_vbios_pramin, true },
> + { "PROM", load_vbios_prom, false },
> + { "PCIROM", load_vbios_pci, true },
> +};
> +#else
> static struct methods nv04_methods[] = {
> { "PROM", load_vbios_prom, false },
> { "PRAMIN", load_vbios_pramin, true },
> { "PCIROM", load_vbios_pci, true },
> };
> +#endif
it pramin is the only method why do you need to redefine this array with different order?
doesn't it fallback to next method when earlier fails?
>
> static struct methods nv50_methods[] = {
> { "PRAMIN", load_vbios_pramin, true },
> diff --git a/drivers/gpu/drm/nouveau/nouveau_state.c b/drivers/gpu/drm/nouveau/nouveau_state.c
> index 58b4680..35d35cc 100644
> --- a/drivers/gpu/drm/nouveau/nouveau_state.c
> +++ b/drivers/gpu/drm/nouveau/nouveau_state.c
> @@ -607,19 +607,49 @@ int nouveau_firstopen(struct drm_device *dev)
> static void nouveau_OF_copy_vbios_to_ramin(struct drm_device *dev)
> {
> #if defined(__powerpc__)
> - int size, i;
> - const uint32_t *bios;
> + /*
> + * Copy BMP Bios to RAMIN, calculate its checksum and append it to Bios.
> + */
> + int size, i, j, unread_bytes, size_int;
> + uint8_t sum = 0;
> + uint8_t checksum = 0;
> + uint32_t last_bytes = 0;
> + const uint32_t *bios = NULL;
> struct device_node *dn = pci_device_to_OF_node(dev->pdev);
> - if (!dn) {
> - NV_INFO(dev, "Unable to get the OF node\n");
> - return;
> - }
>
> + size_int = sizeof(uint32_t);
> bios = of_get_property(dn, "NVDA,BMP", &size);
> + /* write bios data and sum all bytes */
> if (bios) {
> - for (i = 0; i < size; i += 4)
> - nv_wi32(dev, i, bios[i/4]);
> - NV_INFO(dev, "OF bios successfully copied (%d bytes)\n", size);
> + for (j = 0, i = 0; j < (size / size_int); j++, i += 4) {
you are using uint32_t, nv_wi32, incrementing by 4, so why do you need size_int?
> + nv_wi32(dev, i, bios[j]);
> + sum += (bios[j] & 0xFF000000) >> 24;
> + sum += (bios[j] & 0xFF0000) >> 16;
> + sum += (bios[j] & 0xFF00) >> 8;
> + sum += (bios[j] & 0xFF);
> + }
> + unread_bytes = size % size_int;
unwritten_bytes?
> + switch (unread_bytes) {
> + case 0:
> + /* all bytes were read, nothing to do */
> + break;
> + case 3:
> + sum += (bios[j] & 0xFF00) >> 8;
> + last_bytes |= (bios[j] & 0xFF00);
> + case 2:
> + sum += (bios[j] & 0xFF0000) >> 16;
> + last_bytes |= (bios[j] & 0xFF0000);
> + case 1:
> + sum += (bios[j] & 0xFF000000) >> 24;
> + last_bytes |= (bios[j] & 0xFF000000);
> + break;
> + }
comment about "fall through" to the next case would make this code easier to read.
you could move case 0 as the last one
> + /* the checksum is the two's complement of the sum */
> + checksum = ~sum + 1;
> + /* add checksum (1 byte) in the correct position */
> + last_bytes |= (checksum << (24 - unread_bytes * 8));
> + nv_wi32(dev, i, last_bytes);
> + NV_INFO(dev, "OF bios successfully copied (%d bytes) checksum 0x%x\n", size, checksum);
> } else {
> NV_INFO(dev, "Unable to get the OF bios\n");
> }
More information about the Nouveau
mailing list