ambassador.c

来自「linux 内核源代码」· C语言 代码 · 共 2,334 行 · 第 1/5 页

C
2,334
字号
  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 __devinit 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    msleep(4200);    // half second time-out    timeout = 500;    while (!rd_plain (dev, offsetof(amb_mem, mb.loader.ready)))      if (timeout) {	timeout = msleep_interruptible(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 __devinit 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 == ATM_POISON) {    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 __be32 bus_addr(void * addr) {    return cpu_to_be32 (virt_to_bus (addr));}static int __devinit 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)  msleep(2200);  // give the adapter another half second?  timeout = 500;  while (rd_plain (dev, offsetof(amb_mem, doorbell)))    if (timeout) {      timeout = msleep_interruptible(timeout);    } else {      PRINTD (DBG_INIT|DBG_ERR, "adapter init timed out");      return -ETIMEDOUT;    }    return 0;}// get microcode versionstatic void __devinit 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);}  // get end station addressstatic void __devinit 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] = bitrev8(lower4>>(8*i));      else	  esi[i] = bitrev8(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 __devinit 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;       pci_set_drvdata(pci_dev, 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 void setup_pci_dev(struct pci_dev *pci_dev){	unsigned char lat;      	// enable bus master accesses	pci_set_master(pci_dev);	// 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);	}}static int __devinit amb_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent){	amb_dev * dev;	int err;	unsigned int irq;      	err = pci_enable_device(pci_dev);	if (err < 0) {		PRINTK (KERN_ERR, "skipped broken (PLX rev 2) card");		goto out;	}	// read resources from PCI configuration space	irq = pci_dev->irq;	if (pci_dev->device == PCI_DEVICE_ID_MADGE_AMBASSADOR_BAD) {		PRINTK (KERN_ERR, "skipped broken (PLX rev 2) card");		err = -EINVAL;		goto out_disable;	}	PRINTD (DBG_INFO, "found Madge ATM adapter (amb) at"		" IO %llx, IRQ %u, MEM %p",		(unsigned long long)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_disable;	}	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;	}	setup_pci_dev(pci_dev);	// grab (but share) IRQ and install handler	err = request_irq(irq, interrupt_handler, IRQF_SHARED, DEV_LABEL, dev);	if (err < 0) {		PRINTK (KERN_ERR, "request IRQ failed!");		goto out_reset;	}	dev->atm_dev = atm_dev_register (DEV_LABEL, &amb_ops, -1, NULL);	if (!dev->atm_dev) {		PRINTD (DBG_ERR, "failed to register Madge ATM adapter");		err = -EINVAL;		goto out_free_irq;	}	PRINTD (DBG_INFO, "registered Madge ATM adapter (no. %d) (%p) at %p",		dev->atm_dev->number, dev, dev->atm_dev);		dev->atm_dev->dev_data = (void *) dev;	// register our address	amb_esi (dev, dev->atm_dev->esi);	// 0 bits for vpi, 10 bits for vci	dev->atm_dev->ci_range.vpi_bits = NUM_VPI_BITS;	dev->atm_dev->ci_range.vci_bits = NUM_VCI_BITS;	init_timer(&dev->housekeeping);	dev->housekeeping.function = do_housekeeping;	dev->housekeeping.data = (unsigned long) dev;	mod_timer(&dev->housekeeping, jiffies);	// enable host interrupts	interrupts_on (dev);out:	return err;out_free_irq:	free_irq(irq, dev);out_reset:	amb_reset(dev, 0);out_free:	kfree(dev);out_release:	pci_release_region(pci_dev, 1);out_disable:	pci_disable_device(pci_dev);	goto out;}static void __devexit amb_remove_one(struct pci_dev *pci_dev){	struct amb_dev *dev;	dev = pci_get_drvdata(pci_dev);	PRINTD(DBG_INFO|DBG_INIT, "closing %p (atm_dev = %p)", dev, dev->atm_dev);	del_timer_sync(&dev->housekeeping);	// the drain should not be necessary	drain_rx_pools(dev);	interrupts_off(dev);	amb

⌨️ 快捷键说明

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