Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/pci/hotplug/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 12 kB image not shown  

Quelle  cpqphp_nvram.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0+
/*
 * Compaq Hot Plug Controller Driver
 *
 * Copyright (C) 1995,2001 Compaq Computer Corporation
 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
 * Copyright (C) 2001 IBM Corp.
 *
 * All rights reserved.
 *
 * Send feedback to <greg@kroah.com>
 *
 */


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
#include <linux/uaccess.h>
#include "cpqphp.h"
#include "cpqphp_nvram.h"


#define ROM_INT15_PHY_ADDR  0x0FF859
#define READ_EV    0xD8A4
#define WRITE_EV   0xD8A5

struct register_foo {
 union {
  unsigned long lword;  /* eax */
  unsigned short word;  /* ax */

  struct {
   unsigned char low; /* al */
   unsigned char high; /* ah */
  } byte;
 } data;

 unsigned char opcode; /* see below */
 unsigned long length; /* if the reg. is a pointer, how much data */
} __attribute__ ((packed));

struct all_reg {
 struct register_foo eax_reg;
 struct register_foo ebx_reg;
 struct register_foo ecx_reg;
 struct register_foo edx_reg;
 struct register_foo edi_reg;
 struct register_foo esi_reg;
 struct register_foo eflags_reg;
} __attribute__ ((packed));


struct ev_hrt_header {
 u8 Version;
 u8 num_of_ctrl;
 u8 next;
};

struct ev_hrt_ctrl {
 u8 bus;
 u8 device;
 u8 function;
 u8 mem_avail;
 u8 p_mem_avail;
 u8 io_avail;
 u8 bus_avail;
 u8 next;
};


static u8 evbuffer_init;
static u8 evbuffer_length;
static u8 evbuffer[1024];

static void __iomem *compaq_int15_entry_point;

/* lock for ordering int15_bios_call() */
static DEFINE_SPINLOCK(int15_lock);


/* This is a series of function that deals with
 * setting & getting the hotplug resource table in some environment variable.
 */


/*
 * We really shouldn't be doing this unless there is a _very_ good reason to!!!
 * greg k-h
 */



static u32 add_byte(u32 **p_buffer, u8 value, u32 *used, u32 *avail)
{
 u8 **tByte;

 if ((*used + 1) > *avail)
  return(1);

 *((u8 *)*p_buffer) = value;
 tByte = (u8 **)p_buffer;
 (*tByte)++;
 *used += 1;
 return(0);
}


static u32 add_dword(u32 **p_buffer, u32 value, u32 *used, u32 *avail)
{
 if ((*used + 4) > *avail)
  return(1);

 **p_buffer = value;
 (*p_buffer)++;
 *used += 4;
 return(0);
}


/*
 * check_for_compaq_ROM
 *
 * this routine verifies that the ROM OEM string is 'COMPAQ'
 *
 * returns 0 for non-Compaq ROM, 1 for Compaq ROM
 */

static int check_for_compaq_ROM(void __iomem *rom_start)
{
 u8 temp1, temp2, temp3, temp4, temp5, temp6;
 int result = 0;

 temp1 = readb(rom_start + 0xffea + 0);
 temp2 = readb(rom_start + 0xffea + 1);
 temp3 = readb(rom_start + 0xffea + 2);
 temp4 = readb(rom_start + 0xffea + 3);
 temp5 = readb(rom_start + 0xffea + 4);
 temp6 = readb(rom_start + 0xffea + 5);
 if ((temp1 == 'C') &&
     (temp2 == 'O') &&
     (temp3 == 'M') &&
     (temp4 == 'P') &&
     (temp5 == 'A') &&
     (temp6 == 'Q')) {
  result = 1;
 }
 dbg("%s - returned %d\n", __func__, result);
 return result;
}


static u32 access_EV(u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size)
{
 unsigned long flags;
 int op = operation;
 int ret_val;

 if (!compaq_int15_entry_point)
  return -ENODEV;

 spin_lock_irqsave(&int15_lock, flags);
 __asm__ (
  "xorl %%ebx,%%ebx\n" \
  "xorl %%edx,%%edx\n" \
  "pushf\n" \
  "push %%cs\n" \
  "cli\n" \
  "call *%6\n"
  : "=c" (*buf_size), "=a" (ret_val)
  : "a" (op), "c" (*buf_size), "S" (ev_name),
  "D" (buffer), "m" (compaq_int15_entry_point)
  : "%ebx""%edx");
 spin_unlock_irqrestore(&int15_lock, flags);

 return((ret_val & 0xFF00) >> 8);
}


/*
 * load_HRT
 *
 * Read the hot plug Resource Table from NVRAM
 */

static int load_HRT(void __iomem *rom_start)
{
 u32 available;
 u32 temp_dword;
 u8 temp_byte = 0xFF;
 u32 rc;

 if (!check_for_compaq_ROM(rom_start))
  return -ENODEV;

 available = 1024;

 /* Now load the EV */
 temp_dword = available;

 rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword);

 evbuffer_length = temp_dword;

 /* We're maintaining the resource lists so write FF to invalidate old
 * info
 */

 temp_dword = 1;

 rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword);

 return rc;
}


/*
 * store_HRT
 *
 * Save the hot plug Resource Table in NVRAM
 */

static u32 store_HRT(void __iomem *rom_start)
{
 u32 *buffer;
 u32 *pFill;
 u32 usedbytes;
 u32 available;
 u32 temp_dword;
 u32 rc;
 u8 loop;
 u8 numCtrl = 0;
 struct controller *ctrl;
 struct pci_resource *resNode;
 struct ev_hrt_header *p_EV_header;
 struct ev_hrt_ctrl *p_ev_ctrl;

 available = 1024;

 if (!check_for_compaq_ROM(rom_start))
  return(1);

 buffer = (u32 *) evbuffer;

 if (!buffer)
  return(1);

 pFill = buffer;
 usedbytes = 0;

 p_EV_header = (struct ev_hrt_header *) pFill;

 ctrl = cpqhp_ctrl_list;

 /* The revision of this structure */
 rc = add_byte(&pFill, 1 + ctrl->push_flag, &usedbytes, &available);
 if (rc)
  return(rc);

 /* The number of controllers */
 rc = add_byte(&pFill, 1, &usedbytes, &available);
 if (rc)
  return(rc);

 while (ctrl) {
  p_ev_ctrl = (struct ev_hrt_ctrl *) pFill;

  numCtrl++;

  /* The bus number */
  rc = add_byte(&pFill, ctrl->bus, &usedbytes, &available);
  if (rc)
   return(rc);

  /* The device Number */
  rc = add_byte(&pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available);
  if (rc)
   return(rc);

  /* The function Number */
  rc = add_byte(&pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available);
  if (rc)
   return(rc);

  /* Skip the number of available entries */
  rc = add_dword(&pFill, 0, &usedbytes, &available);
  if (rc)
   return(rc);

  /* Figure out memory Available */

  resNode = ctrl->mem_head;

  loop = 0;

  while (resNode) {
   loop++;

   /* base */
   rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
   if (rc)
    return(rc);

   /* length */
   rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
   if (rc)
    return(rc);

   resNode = resNode->next;
  }

  /* Fill in the number of entries */
  p_ev_ctrl->mem_avail = loop;

  /* Figure out prefetchable memory Available */

  resNode = ctrl->p_mem_head;

  loop = 0;

  while (resNode) {
   loop++;

   /* base */
   rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
   if (rc)
    return(rc);

   /* length */
   rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
   if (rc)
    return(rc);

   resNode = resNode->next;
  }

  /* Fill in the number of entries */
  p_ev_ctrl->p_mem_avail = loop;

  /* Figure out IO Available */

  resNode = ctrl->io_head;

  loop = 0;

  while (resNode) {
   loop++;

   /* base */
   rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
   if (rc)
    return(rc);

   /* length */
   rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
   if (rc)
    return(rc);

   resNode = resNode->next;
  }

  /* Fill in the number of entries */
  p_ev_ctrl->io_avail = loop;

  /* Figure out bus Available */

  resNode = ctrl->bus_head;

  loop = 0;

  while (resNode) {
   loop++;

   /* base */
   rc = add_dword(&pFill, resNode->base, &usedbytes, &available);
   if (rc)
    return(rc);

   /* length */
   rc = add_dword(&pFill, resNode->length, &usedbytes, &available);
   if (rc)
    return(rc);

   resNode = resNode->next;
  }

  /* Fill in the number of entries */
  p_ev_ctrl->bus_avail = loop;

  ctrl = ctrl->next;
 }

 p_EV_header->num_of_ctrl = numCtrl;

 /* Now store the EV */

 temp_dword = usedbytes;

 rc = access_EV(WRITE_EV, "CQTHPS", (u8 *) buffer, &temp_dword);

 dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword);

 evbuffer_length = temp_dword;

 if (rc) {
  err(msg_unable_to_save);
  return(1);
 }

 return(0);
}


void compaq_nvram_init(void __iomem *rom_start)
{
 if (rom_start)
  compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);

 dbg("int15 entry = %p\n", compaq_int15_entry_point);
}


int compaq_nvram_load(void __iomem *rom_start, struct controller *ctrl)
{
 u8 bus, device, function;
 u8 nummem, numpmem, numio, numbus;
 u32 rc;
 u8 *p_byte;
 struct pci_resource *mem_node;
 struct pci_resource *p_mem_node;
 struct pci_resource *io_node;
 struct pci_resource *bus_node;
 struct ev_hrt_ctrl *p_ev_ctrl;
 struct ev_hrt_header *p_EV_header;

 if (!evbuffer_init) {
  /* Read the resource list information in from NVRAM */
  if (load_HRT(rom_start))
   memset(evbuffer, 0, 1024);

  evbuffer_init = 1;
 }

 /* If we saved information in NVRAM, use it now */
 p_EV_header = (struct ev_hrt_header *) evbuffer;

 /* The following code is for systems where version 1.0 of this
 * driver has been loaded, but doesn't support the hardware.
 * In that case, the driver would incorrectly store something
 * in NVRAM.
 */

 if ((p_EV_header->Version == 2) ||
     ((p_EV_header->Version == 1) && !ctrl->push_flag)) {
  p_byte = &(p_EV_header->next);

  p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next);

  p_byte += 3;

  if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
   return 2;

  bus = p_ev_ctrl->bus;
  device = p_ev_ctrl->device;
  function = p_ev_ctrl->function;

  while ((bus != ctrl->bus) ||
         (device != PCI_SLOT(ctrl->pci_dev->devfn)) ||
         (function != PCI_FUNC(ctrl->pci_dev->devfn))) {
   nummem = p_ev_ctrl->mem_avail;
   numpmem = p_ev_ctrl->p_mem_avail;
   numio = p_ev_ctrl->io_avail;
   numbus = p_ev_ctrl->bus_avail;

   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
    return 2;

   /* Skip forward to the next entry */
   p_byte += (nummem + numpmem + numio + numbus) * 8;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
    return 2;

   p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte;

   p_byte += 3;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
    return 2;

   bus = p_ev_ctrl->bus;
   device = p_ev_ctrl->device;
   function = p_ev_ctrl->function;
  }

  nummem = p_ev_ctrl->mem_avail;
  numpmem = p_ev_ctrl->p_mem_avail;
  numio = p_ev_ctrl->io_avail;
  numbus = p_ev_ctrl->bus_avail;

  p_byte += 4;

  if (p_byte > ((u8 *)p_EV_header + evbuffer_length))
   return 2;

  while (nummem--) {
   mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);

   if (!mem_node)
    break;

   mem_node->base = *(u32 *)p_byte;
   dbg("mem base = %8.8x\n", mem_node->base);
   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    kfree(mem_node);
    return 2;
   }

   mem_node->length = *(u32 *)p_byte;
   dbg("mem length = %8.8x\n", mem_node->length);
   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    kfree(mem_node);
    return 2;
   }

   mem_node->next = ctrl->mem_head;
   ctrl->mem_head = mem_node;
  }

  while (numpmem--) {
   p_mem_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);

   if (!p_mem_node)
    break;

   p_mem_node->base = *(u32 *)p_byte;
   dbg("pre-mem base = %8.8x\n", p_mem_node->base);
   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    kfree(p_mem_node);
    return 2;
   }

   p_mem_node->length = *(u32 *)p_byte;
   dbg("pre-mem length = %8.8x\n", p_mem_node->length);
   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    kfree(p_mem_node);
    return 2;
   }

   p_mem_node->next = ctrl->p_mem_head;
   ctrl->p_mem_head = p_mem_node;
  }

  while (numio--) {
   io_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);

   if (!io_node)
    break;

   io_node->base = *(u32 *)p_byte;
   dbg("io base = %8.8x\n", io_node->base);
   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    kfree(io_node);
    return 2;
   }

   io_node->length = *(u32 *)p_byte;
   dbg("io length = %8.8x\n", io_node->length);
   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    kfree(io_node);
    return 2;
   }

   io_node->next = ctrl->io_head;
   ctrl->io_head = io_node;
  }

  while (numbus--) {
   bus_node = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);

   if (!bus_node)
    break;

   bus_node->base = *(u32 *)p_byte;
   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    kfree(bus_node);
    return 2;
   }

   bus_node->length = *(u32 *)p_byte;
   p_byte += 4;

   if (p_byte > ((u8 *)p_EV_header + evbuffer_length)) {
    kfree(bus_node);
    return 2;
   }

   bus_node->next = ctrl->bus_head;
   ctrl->bus_head = bus_node;
  }

  /* If all of the following fail, we don't have any resources for
 * hot plug add
 */

  rc = 1;
  rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head));
  rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head));
  rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head));
  rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head));

  if (rc)
   return(rc);
 } else {
  if ((evbuffer[0] != 0) && (!ctrl->push_flag))
   return 1;
 }

 return 0;
}


int compaq_nvram_store(void __iomem *rom_start)
{
 int rc = 1;

 if (rom_start == NULL)
  return -ENODEV;

 if (evbuffer_init) {
  rc = store_HRT(rom_start);
  if (rc)
   err(msg_unable_to_save);
 }
 return rc;
}


Messung V0.5
C=93 H=88 G=90

¤ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.