cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mga_warp.c (4776B)


      1/* mga_warp.c -- Matrox G200/G400 WARP engine management -*- linux-c -*-
      2 * Created: Thu Jan 11 21:29:32 2001 by gareth@valinux.com
      3 *
      4 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
      5 * All Rights Reserved.
      6 *
      7 * Permission is hereby granted, free of charge, to any person obtaining a
      8 * copy of this software and associated documentation files (the "Software"),
      9 * to deal in the Software without restriction, including without limitation
     10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     11 * and/or sell copies of the Software, and to permit persons to whom the
     12 * Software is furnished to do so, subject to the following conditions:
     13 *
     14 * The above copyright notice and this permission notice (including the next
     15 * paragraph) shall be included in all copies or substantial portions of the
     16 * Software.
     17 *
     18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     21 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     24 * OTHER DEALINGS IN THE SOFTWARE.
     25 *
     26 * Authors:
     27 *    Gareth Hughes <gareth@valinux.com>
     28 */
     29
     30#include <linux/firmware.h>
     31#include <linux/ihex.h>
     32#include <linux/module.h>
     33#include <linux/platform_device.h>
     34
     35#include "mga_drv.h"
     36
     37#define FIRMWARE_G200 "matrox/g200_warp.fw"
     38#define FIRMWARE_G400 "matrox/g400_warp.fw"
     39
     40MODULE_FIRMWARE(FIRMWARE_G200);
     41MODULE_FIRMWARE(FIRMWARE_G400);
     42
     43#define MGA_WARP_CODE_ALIGN		256	/* in bytes */
     44
     45#define WARP_UCODE_SIZE(size)		ALIGN(size, MGA_WARP_CODE_ALIGN)
     46
     47int mga_warp_install_microcode(drm_mga_private_t *dev_priv)
     48{
     49	unsigned char *vcbase = dev_priv->warp->handle;
     50	unsigned long pcbase = dev_priv->warp->offset;
     51	const char *firmware_name;
     52	struct platform_device *pdev;
     53	const struct firmware *fw = NULL;
     54	const struct ihex_binrec *rec;
     55	unsigned int size;
     56	int n_pipes, where;
     57	int rc = 0;
     58
     59	switch (dev_priv->chipset) {
     60	case MGA_CARD_TYPE_G400:
     61	case MGA_CARD_TYPE_G550:
     62		firmware_name = FIRMWARE_G400;
     63		n_pipes = MGA_MAX_G400_PIPES;
     64		break;
     65	case MGA_CARD_TYPE_G200:
     66		firmware_name = FIRMWARE_G200;
     67		n_pipes = MGA_MAX_G200_PIPES;
     68		break;
     69	default:
     70		return -EINVAL;
     71	}
     72
     73	pdev = platform_device_register_simple("mga_warp", 0, NULL, 0);
     74	if (IS_ERR(pdev)) {
     75		DRM_ERROR("mga: Failed to register microcode\n");
     76		return PTR_ERR(pdev);
     77	}
     78	rc = request_ihex_firmware(&fw, firmware_name, &pdev->dev);
     79	platform_device_unregister(pdev);
     80	if (rc) {
     81		DRM_ERROR("mga: Failed to load microcode \"%s\"\n",
     82			  firmware_name);
     83		return rc;
     84	}
     85
     86	size = 0;
     87	where = 0;
     88	for (rec = (const struct ihex_binrec *)fw->data;
     89	     rec;
     90	     rec = ihex_next_binrec(rec)) {
     91		size += WARP_UCODE_SIZE(be16_to_cpu(rec->len));
     92		where++;
     93	}
     94
     95	if (where != n_pipes) {
     96		DRM_ERROR("mga: Invalid microcode \"%s\"\n", firmware_name);
     97		rc = -EINVAL;
     98		goto out;
     99	}
    100	size = PAGE_ALIGN(size);
    101	DRM_DEBUG("MGA ucode size = %d bytes\n", size);
    102	if (size > dev_priv->warp->size) {
    103		DRM_ERROR("microcode too large! (%u > %lu)\n",
    104			  size, dev_priv->warp->size);
    105		rc = -ENOMEM;
    106		goto out;
    107	}
    108
    109	memset(dev_priv->warp_pipe_phys, 0, sizeof(dev_priv->warp_pipe_phys));
    110
    111	where = 0;
    112	for (rec = (const struct ihex_binrec *)fw->data;
    113	     rec;
    114	     rec = ihex_next_binrec(rec)) {
    115		unsigned int src_size, dst_size;
    116
    117		DRM_DEBUG(" pcbase = 0x%08lx  vcbase = %p\n", pcbase, vcbase);
    118		dev_priv->warp_pipe_phys[where] = pcbase;
    119		src_size = be16_to_cpu(rec->len);
    120		dst_size = WARP_UCODE_SIZE(src_size);
    121		memcpy(vcbase, rec->data, src_size);
    122		pcbase += dst_size;
    123		vcbase += dst_size;
    124		where++;
    125	}
    126
    127out:
    128	release_firmware(fw);
    129	return rc;
    130}
    131
    132#define WMISC_EXPECTED		(MGA_WUCODECACHE_ENABLE | MGA_WMASTER_ENABLE)
    133
    134int mga_warp_init(drm_mga_private_t *dev_priv)
    135{
    136	u32 wmisc;
    137
    138	/* FIXME: Get rid of these damned magic numbers...
    139	 */
    140	switch (dev_priv->chipset) {
    141	case MGA_CARD_TYPE_G400:
    142	case MGA_CARD_TYPE_G550:
    143		MGA_WRITE(MGA_WIADDR2, MGA_WMODE_SUSPEND);
    144		MGA_WRITE(MGA_WGETMSB, 0x00000E00);
    145		MGA_WRITE(MGA_WVRTXSZ, 0x00001807);
    146		MGA_WRITE(MGA_WACCEPTSEQ, 0x18000000);
    147		break;
    148	case MGA_CARD_TYPE_G200:
    149		MGA_WRITE(MGA_WIADDR, MGA_WMODE_SUSPEND);
    150		MGA_WRITE(MGA_WGETMSB, 0x1606);
    151		MGA_WRITE(MGA_WVRTXSZ, 7);
    152		break;
    153	default:
    154		return -EINVAL;
    155	}
    156
    157	MGA_WRITE(MGA_WMISC, (MGA_WUCODECACHE_ENABLE |
    158			      MGA_WMASTER_ENABLE | MGA_WCACHEFLUSH_ENABLE));
    159	wmisc = MGA_READ(MGA_WMISC);
    160	if (wmisc != WMISC_EXPECTED) {
    161		DRM_ERROR("WARP engine config failed! 0x%x != 0x%x\n",
    162			  wmisc, WMISC_EXPECTED);
    163		return -EINVAL;
    164	}
    165
    166	return 0;
    167}