ambassador.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,331 行 · 第 1/5 页

C
2,331
字号
    PRINTD (DBG_FLOW|DBG_LOAD, "get_loader_version");    res = do_loader_command (lb, dev, get_version_number);  if (res)    return res;  if (version)    *version = be32_to_cpu (lb->payload.version);  return 0;}/* loader: write memory data blocks */static int __init loader_write (loader_block * lb,				const amb_dev * dev, const u32 * data,				u32 address, unsigned int count) {  unsigned int i;  transfer_block * tb = &lb->payload.transfer;    PRINTD (DBG_FLOW|DBG_LOAD, "loader_write");    if (count > MAX_TRANSFER_DATA)    return -EINVAL;  tb->address = cpu_to_be32 (address);  tb->count = cpu_to_be32 (count);  for (i = 0; i < count; ++i)    tb->data[i] = cpu_to_be32 (data[i]);  return do_loader_command (lb, dev, write_adapter_memory);}/* loader: verify memory data blocks */static int __init loader_verify (loader_block * lb,				 const amb_dev * dev, const u32 * data,				 u32 address, unsigned int count) {  unsigned int i;  transfer_block * tb = &lb->payload.transfer;  int res;    PRINTD (DBG_FLOW|DBG_LOAD, "loader_verify");    if (count > MAX_TRANSFER_DATA)    return -EINVAL;  tb->address = cpu_to_be32 (address);  tb->count = cpu_to_be32 (count);  res = do_loader_command (lb, dev, read_adapter_memory);  if (!res)    for (i = 0; i < count; ++i)      if (tb->data[i] != cpu_to_be32 (data[i])) {	res = -EINVAL;	break;      }  return res;}/* loader: start microcode */static int __init loader_start (loader_block * lb,				const amb_dev * dev, u32 address) {  PRINTD (DBG_FLOW|DBG_LOAD, "loader_start");    lb->payload.start = cpu_to_be32 (address);  return do_loader_command (lb, dev, adapter_start);}/********** reset card **********/static inline void sf (const char * msg){	PRINTK (KERN_ERR, "self-test failed: %s", msg);}static int amb_reset (amb_dev * dev, int diags) {  u32 word;    PRINTD (DBG_FLOW|DBG_LOAD, "amb_reset");    word = rd_plain (dev, offsetof(amb_mem, reset_control));  // put card into reset state  wr_plain (dev, offsetof(amb_mem, reset_control), word | AMB_RESET_BITS);  // wait a short while  udelay (10);#if 1  // put card into known good state  wr_plain (dev, offsetof(amb_mem, interrupt_control), AMB_DOORBELL_BITS);  // clear all interrupts just in case  wr_plain (dev, offsetof(amb_mem, interrupt), -1);#endif  // clear self-test done flag  wr_plain (dev, offsetof(amb_mem, mb.loader.ready), 0);  // take card out of reset state  wr_plain (dev, offsetof(amb_mem, reset_control), word &~ AMB_RESET_BITS);    if (diags) {     unsigned long timeout;    // 4.2 second wait    timeout = HZ*42/10;    while (timeout) {      set_current_state(TASK_UNINTERRUPTIBLE);      timeout = schedule_timeout (timeout);    }    // half second time-out    timeout = HZ/2;    while (!rd_plain (dev, offsetof(amb_mem, mb.loader.ready)))      if (timeout) {        set_current_state(TASK_UNINTERRUPTIBLE);	timeout = schedule_timeout (timeout);      } else {	PRINTD (DBG_LOAD|DBG_ERR, "reset timed out");	return -ETIMEDOUT;      }        // get results of self-test    // XXX double check byte-order    word = rd_mem (dev, offsetof(amb_mem, mb.loader.result));    if (word & SELF_TEST_FAILURE) {      if (word & GPINT_TST_FAILURE)	sf ("interrupt");      if (word & SUNI_DATA_PATTERN_FAILURE)	sf ("SUNI data pattern");      if (word & SUNI_DATA_BITS_FAILURE)	sf ("SUNI data bits");      if (word & SUNI_UTOPIA_FAILURE)	sf ("SUNI UTOPIA interface");      if (word & SUNI_FIFO_FAILURE)	sf ("SUNI cell buffer FIFO");      if (word & SRAM_FAILURE)	sf ("bad SRAM");      // better return value?      return -EIO;    }      }  return 0;}/********** transfer and start the microcode **********/static int __init ucode_init (loader_block * lb, amb_dev * dev) {  unsigned int i = 0;  unsigned int total = 0;  const u32 * pointer = ucode_data;  u32 address;  unsigned int count;  int res;    PRINTD (DBG_FLOW|DBG_LOAD, "ucode_init");    while (address = ucode_regions[i].start,	 count = ucode_regions[i].count) {    PRINTD (DBG_LOAD, "starting region (%x, %u)", address, count);    while (count) {      unsigned int words;      if (count <= MAX_TRANSFER_DATA)	words = count;      else	words = MAX_TRANSFER_DATA;      total += words;      res = loader_write (lb, dev, pointer, address, words);      if (res)	return res;      res = loader_verify (lb, dev, pointer, address, words);      if (res)	return res;      count -= words;      address += sizeof(u32) * words;      pointer += words;    }    i += 1;  }  if (*pointer == 0xdeadbeef) {    return loader_start (lb, dev, ucode_start);  } else {    // cast needed as there is no %? for pointer differnces    PRINTD (DBG_LOAD|DBG_ERR,	    "offset=%li, *pointer=%x, address=%x, total=%u",	    (long) (pointer - ucode_data), *pointer, address, total);    PRINTK (KERN_ERR, "incorrect microcode data");    return -ENOMEM;  }}/********** give adapter parameters **********/  static inline u32 bus_addr(void * addr) {    return cpu_to_be32 (virt_to_bus (addr));}static int __init amb_talk (amb_dev * dev) {  adap_talk_block a;  unsigned char pool;  unsigned long timeout;    PRINTD (DBG_FLOW, "amb_talk %p", dev);    a.command_start = bus_addr (dev->cq.ptrs.start);  a.command_end   = bus_addr (dev->cq.ptrs.limit);  a.tx_start      = bus_addr (dev->txq.in.start);  a.tx_end        = bus_addr (dev->txq.in.limit);  a.txcom_start   = bus_addr (dev->txq.out.start);  a.txcom_end     = bus_addr (dev->txq.out.limit);    for (pool = 0; pool < NUM_RX_POOLS; ++pool) {    // the other "a" items are set up by the adapter    a.rec_struct[pool].buffer_start = bus_addr (dev->rxq[pool].in.start);    a.rec_struct[pool].buffer_end   = bus_addr (dev->rxq[pool].in.limit);    a.rec_struct[pool].rx_start     = bus_addr (dev->rxq[pool].out.start);    a.rec_struct[pool].rx_end       = bus_addr (dev->rxq[pool].out.limit);    a.rec_struct[pool].buffer_size = cpu_to_be32 (dev->rxq[pool].buffer_size);  }  #ifdef AMB_NEW_MICROCODE  // disable fast PLX prefetching  a.init_flags = 0;#endif    // pass the structure  wr_mem (dev, offsetof(amb_mem, doorbell), virt_to_bus (&a));    // 2.2 second wait (must not touch doorbell during 2 second DMA test)  timeout = HZ*22/10;  while (timeout)    timeout = schedule_timeout (timeout);  // give the adapter another half second?  timeout = HZ/2;  while (rd_plain (dev, offsetof(amb_mem, doorbell)))    if (timeout) {      timeout = schedule_timeout (timeout);    } else {      PRINTD (DBG_INIT|DBG_ERR, "adapter init timed out");      return -ETIMEDOUT;    }    return 0;}// get microcode versionstatic void __init amb_ucode_version (amb_dev * dev) {  u32 major;  u32 minor;  command cmd;  cmd.request = cpu_to_be32 (SRB_GET_VERSION);  while (command_do (dev, &cmd)) {    set_current_state(TASK_UNINTERRUPTIBLE);    schedule();  }  major = be32_to_cpu (cmd.args.version.major);  minor = be32_to_cpu (cmd.args.version.minor);  PRINTK (KERN_INFO, "microcode version is %u.%u", major, minor);}  // swap bits within byte to get Ethernet orderingu8 bit_swap (u8 byte){    const u8 swap[] = {      0x0, 0x8, 0x4, 0xc,      0x2, 0xa, 0x6, 0xe,      0x1, 0x9, 0x5, 0xd,      0x3, 0xb, 0x7, 0xf    };    return ((swap[byte & 0xf]<<4) | swap[byte>>4]);}// get end station addressstatic void __init amb_esi (amb_dev * dev, u8 * esi) {  u32 lower4;  u16 upper2;  command cmd;    cmd.request = cpu_to_be32 (SRB_GET_BIA);  while (command_do (dev, &cmd)) {    set_current_state(TASK_UNINTERRUPTIBLE);    schedule();  }  lower4 = be32_to_cpu (cmd.args.bia.lower4);  upper2 = be32_to_cpu (cmd.args.bia.upper2);  PRINTD (DBG_LOAD, "BIA: lower4: %08x, upper2 %04x", lower4, upper2);    if (esi) {    unsigned int i;        PRINTDB (DBG_INIT, "ESI:");    for (i = 0; i < ESI_LEN; ++i) {      if (i < 4)	  esi[i] = bit_swap (lower4>>(8*i));      else	  esi[i] = bit_swap (upper2>>(8*(i-4)));      PRINTDM (DBG_INIT, " %02x", esi[i]);    }        PRINTDE (DBG_INIT, "");  }    return;}  static void fixup_plx_window (amb_dev *dev, loader_block *lb){	// fix up the PLX-mapped window base address to match the block	unsigned long blb;	u32 mapreg;	blb = virt_to_bus(lb);	// the kernel stack had better not ever cross a 1Gb boundary!	mapreg = rd_plain (dev, offsetof(amb_mem, stuff[10]));	mapreg &= ~onegigmask;	mapreg |= blb & onegigmask;	wr_plain (dev, offsetof(amb_mem, stuff[10]), mapreg);	return;}static int __init amb_init (amb_dev * dev){  loader_block lb;    u32 version;    if (amb_reset (dev, 1)) {    PRINTK (KERN_ERR, "card reset failed!");  } else {    fixup_plx_window (dev, &lb);        if (get_loader_version (&lb, dev, &version)) {      PRINTK (KERN_INFO, "failed to get loader version");    } else {      PRINTK (KERN_INFO, "loader version is %08x", version);            if (ucode_init (&lb, dev)) {	PRINTK (KERN_ERR, "microcode failure");      } else if (create_queues (dev, cmds, txs, rxs, rxs_bs)) {	PRINTK (KERN_ERR, "failed to get memory for queues");      } else {		if (amb_talk (dev)) {	  PRINTK (KERN_ERR, "adapter did not accept queues");	} else {	  	  amb_ucode_version (dev);	  return 0;	  	} /* amb_talk */		destroy_queues (dev);      } /* create_queues, ucode_init */            amb_reset (dev, 0);    } /* get_loader_version */      } /* amb_reset */    return -EINVAL;}static void setup_dev(amb_dev *dev, struct pci_dev *pci_dev) {      unsigned char pool;      memset (dev, 0, sizeof(amb_dev));            // set up known dev items straight away      dev->pci_dev = pci_dev;             dev->iobase = pci_resource_start (pci_dev, 1);      dev->irq = pci_dev->irq;       dev->membase = bus_to_virt(pci_resource_start(pci_dev, 0));            // flags (currently only dead)      dev->flags = 0;            // Allocate cell rates (fibre)      // ATM_OC3_PCR = 1555200000/8/270*260/53 - 29/53      // to be really pedantic, this should be ATM_OC3c_PCR      dev->tx_avail = ATM_OC3_PCR;      dev->rx_avail = ATM_OC3_PCR;      #ifdef FILL_RX_POOLS_IN_BH      // initialise bottom half      INIT_WORK(&dev->bh, (void (*)(void *)) fill_rx_pools, dev);#endif            // semaphore for txer/rxer modifications - we cannot use a      // spinlock as the critical region needs to switch processes      init_MUTEX (&dev->vcc_sf);      // queue manipulation spinlocks; we want atomic reads and      // writes to the queue descriptors (handles IRQ and SMP)      // consider replacing "int pending" -> "atomic_t available"      // => problem related to who gets to move queue pointers      spin_lock_init (&dev->cq.lock);      spin_lock_init (&dev->txq.lock);      for (pool = 0; pool < NUM_RX_POOLS; ++pool)	spin_lock_init (&dev->rxq[pool].lock);}static int setup_pci_dev(struct pci_dev *pci_dev){	unsigned char lat;	int ret;      	// enable bus master accesses	pci_set_master(pci_dev);      	ret = pci_enable_device(pci_dev);	if (ret < 0)		goto out;	// frobnicate latency (upwards, usually)	pci_read_config_byte (pci_dev, PCI_LATENCY_TIMER, &lat);	if (!pci_lat)		pci_lat = (lat < MIN_PCI_LATENCY) ? MIN_PCI_LATENCY : lat;	if (lat != pci_lat) {		PRINTK (KERN_INFO, "Changing PCI latency timer from %hu to %hu",			lat, pci_lat);		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, pci_lat);	}out:	return ret;}static int __init do_pci_device(struct pci_dev *pci_dev){	amb_dev * dev;	int err;	// read resources from PCI configuration space	u8 irq = pci_dev->irq;	PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"		" IO %x, IRQ %u, MEM %p", pci_resource_start(pci_dev, 1),		irq, bus_to_virt(pci_resource_start(pci_dev, 0)));	// check IO region	err = pci_request_region(pci_dev, 1, DEV_LABEL);	if (err < 0) {		PRINTK (KERN_ERR, "IO range already in use!");		goto out;	}	dev = kmalloc (sizeof(amb_dev), GFP_KERNEL);	if (!dev) {		PRINTK (KERN_ERR, "out of memory!");		err = -ENOMEM;		goto out_release;	}	setup_dev(dev, pci_dev);	err = amb_init(dev);	if (err < 0) {		PRINTK (KERN_ERR, "adapter initialisation failure");		goto out_free;	}	err = setup_pci_dev(pci_dev);	if (err < 0)		goto out_reset;	// grab (but share) IRQ and install handler	err = request_irq(irq, interrupt_handler, SA_SHIRQ, DEV_LABEL, dev);	if (err < 0) {		PRINTK (KERN_ERR, "request IRQ failed!");		goto out_disable;	}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?