Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

p54: enhance firmware parser to reduce memory waste

This patch greatly reduces one of biggest memory waste in the driver.

The firmware headers provides the right values for extra head-/tailroom
and mtu size which are usually much lower than the old hardcoded ones.

Signed-off-by: Christian Lamparter <chunkeey@web.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>

authored by

Christian Lamparter and committed by
John W. Linville
4e416a6f 0c25970d

+69 -27
+4 -2
drivers/net/wireless/p54/p54.h
··· 39 39 } __attribute__ ((packed)); 40 40 41 41 #define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */) 42 - #define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 ) 43 42 44 43 #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 45 44 ··· 52 53 void (*stop)(struct ieee80211_hw *dev); 53 54 int mode; 54 55 u16 seqno; 56 + u16 rx_mtu; 57 + u8 headroom; 58 + u8 tailroom; 55 59 struct mutex conf_mutex; 56 60 u8 mac_addr[ETH_ALEN]; 57 61 u8 bssid[ETH_ALEN]; ··· 72 70 }; 73 71 74 72 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); 75 - void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); 73 + int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); 76 74 int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len); 77 75 void p54_fill_eeprom_readback(struct p54_control_hdr *hdr); 78 76 struct ieee80211_hw *p54_init_common(size_t priv_data_len);
+24 -12
drivers/net/wireless/p54/p54common.c
··· 66 66 .n_bitrates = ARRAY_SIZE(p54_rates), 67 67 }; 68 68 69 - 70 - void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) 69 + int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) 71 70 { 72 71 struct p54_common *priv = dev->priv; 73 72 struct bootrec_exp_if *exp_if; ··· 78 79 int i; 79 80 80 81 if (priv->rx_start) 81 - return; 82 + return 0; 82 83 83 84 while (data < end_data && *data) 84 85 data++; ··· 116 117 if (strnlen((unsigned char*)bootrec->data, 24) < 24) 117 118 fw_version = (unsigned char*)bootrec->data; 118 119 break; 119 - case BR_CODE_DESCR: 120 - priv->rx_start = le32_to_cpu(((__le32 *)bootrec->data)[1]); 120 + case BR_CODE_DESCR: { 121 + struct bootrec_desc *desc = 122 + (struct bootrec_desc *)bootrec->data; 123 + priv->rx_start = le32_to_cpu(desc->rx_start); 121 124 /* FIXME add sanity checking */ 122 - priv->rx_end = le32_to_cpu(((__le32 *)bootrec->data)[2]) - 0x3500; 125 + priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; 126 + priv->headroom = desc->headroom; 127 + priv->tailroom = desc->tailroom; 128 + if (bootrec->len == 11) 129 + priv->rx_mtu = (size_t) le16_to_cpu( 130 + (__le16)bootrec->data[10]); 131 + else 132 + priv->rx_mtu = (size_t) 133 + 0x620 - priv->tx_hdr_len; 123 134 break; 135 + } 124 136 case BR_CODE_EXPOSED_IF: 125 137 exp_if = (struct bootrec_exp_if *) bootrec->data; 126 138 for (i = 0; i < (len * sizeof(*exp_if) / 4); i++) ··· 162 152 priv->tx_stats[7].limit = 1; 163 153 dev->queues = 4; 164 154 } 155 + 156 + return 0; 165 157 } 166 158 EXPORT_SYMBOL_GPL(p54_parse_firmware); 167 159 ··· 440 428 struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; 441 429 struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data; 442 430 struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; 443 - u32 addr = le32_to_cpu(hdr->req_id) - 0x70; 431 + u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; 444 432 struct memrecord *range = NULL; 445 433 u32 freed = 0; 446 434 u32 last_addr = priv->rx_start; ··· 562 550 u32 target_addr = priv->rx_start; 563 551 unsigned long flags; 564 552 unsigned int left; 565 - len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */ 553 + len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; 566 554 567 555 spin_lock_irqsave(&priv->tx_queue.lock, flags); 568 556 left = skb_queue_len(&priv->tx_queue); ··· 597 585 range->start_addr = target_addr; 598 586 range->end_addr = target_addr + len; 599 587 __skb_queue_after(&priv->tx_queue, target_skb, skb); 600 - if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 + 588 + if (largest_hole < priv->rx_mtu + priv->headroom + 589 + priv->tailroom + 601 590 sizeof(struct p54_control_hdr)) 602 591 ieee80211_stop_queues(dev); 603 592 } 604 593 spin_unlock_irqrestore(&priv->tx_queue.lock, flags); 605 594 606 - data->req_id = cpu_to_le32(target_addr + 0x70); 595 + data->req_id = cpu_to_le32(target_addr + priv->headroom); 607 596 } 608 597 609 598 static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ··· 717 704 filter->antenna = antenna; 718 705 filter->magic3 = cpu_to_le32(magic3); 719 706 filter->rx_addr = cpu_to_le32(priv->rx_end); 720 - filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */ 707 + filter->max_rx = cpu_to_le16(priv->rx_mtu); 721 708 filter->rxhw = priv->rxhw; 722 709 filter->magic8 = cpu_to_le16(magic8); 723 710 filter->magic9 = cpu_to_le16(magic9); ··· 1097 1084 priv->tx_stats[3].limit = 1; 1098 1085 priv->tx_stats[4].limit = 5; 1099 1086 dev->queues = 1; 1100 - 1101 1087 dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + 1102 1088 sizeof(struct p54_tx_control_allocdata); 1103 1089
+11
drivers/net/wireless/p54/p54common.h
··· 29 29 __le16 top_compat; 30 30 } __attribute__((packed)); 31 31 32 + struct bootrec_desc { 33 + __le16 modes; 34 + __le16 flags; 35 + __le32 rx_start; 36 + __le32 rx_end; 37 + u8 headroom; 38 + u8 tailroom; 39 + u8 unimportant[6]; 40 + u8 rates[16]; 41 + } __attribute__((packed)); 42 + 32 43 #define BR_CODE_MIN 0x80000000 33 44 #define BR_CODE_COMPONENT_ID 0x80000001 34 45 #define BR_CODE_COMPONENT_VERSION 0x80000002
+15 -8
drivers/net/wireless/p54/p54pci.c
··· 81 81 return err; 82 82 } 83 83 84 - p54_parse_firmware(dev, fw_entry); 84 + err = p54_parse_firmware(dev, fw_entry); 85 + if (err) { 86 + release_firmware(fw_entry); 87 + return err; 88 + } 85 89 86 90 data = (__le32 *) fw_entry->data; 87 91 remains = fw_entry->size; ··· 262 258 if (!desc->host_addr) { 263 259 struct sk_buff *skb; 264 260 dma_addr_t mapping; 265 - skb = dev_alloc_skb(MAX_RX_SIZE); 261 + skb = dev_alloc_skb(priv->common.rx_mtu + 32); 266 262 if (!skb) 267 263 break; 268 264 269 265 mapping = pci_map_single(priv->pdev, 270 266 skb_tail_pointer(skb), 271 - MAX_RX_SIZE, 267 + priv->common.rx_mtu + 32, 272 268 PCI_DMA_FROMDEVICE); 273 269 desc->host_addr = cpu_to_le32(mapping); 274 270 desc->device_addr = 0; // FIXME: necessary? 275 - desc->len = cpu_to_le16(MAX_RX_SIZE); 271 + desc->len = cpu_to_le16(priv->common.rx_mtu + 32); 276 272 desc->flags = 0; 277 273 rx_buf[i] = skb; 278 274 } ··· 315 311 if (p54_rx(dev, skb)) { 316 312 pci_unmap_single(priv->pdev, 317 313 le32_to_cpu(desc->host_addr), 318 - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); 314 + priv->common.rx_mtu + 32, 315 + PCI_DMA_FROMDEVICE); 319 316 rx_buf[i] = NULL; 320 317 desc->host_addr = 0; 321 318 } else { 322 319 skb_trim(skb, 0); 323 - desc->len = cpu_to_le16(MAX_RX_SIZE); 320 + desc->len = cpu_to_le16(priv->common.rx_mtu + 32); 324 321 } 325 322 326 323 i++; ··· 539 534 if (desc->host_addr) 540 535 pci_unmap_single(priv->pdev, 541 536 le32_to_cpu(desc->host_addr), 542 - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); 537 + priv->common.rx_mtu + 32, 538 + PCI_DMA_FROMDEVICE); 543 539 kfree_skb(priv->rx_buf_data[i]); 544 540 priv->rx_buf_data[i] = NULL; 545 541 } ··· 550 544 if (desc->host_addr) 551 545 pci_unmap_single(priv->pdev, 552 546 le32_to_cpu(desc->host_addr), 553 - MAX_RX_SIZE, PCI_DMA_FROMDEVICE); 547 + priv->common.rx_mtu + 32, 548 + PCI_DMA_FROMDEVICE); 554 549 kfree_skb(priv->rx_buf_mgmt[i]); 555 550 priv->rx_buf_mgmt[i] = NULL; 556 551 }
+15 -5
drivers/net/wireless/p54/p54usb.c
··· 95 95 skb_pull(skb, sizeof(struct net2280_tx_hdr)); 96 96 97 97 if (p54_rx(dev, skb)) { 98 - skb = dev_alloc_skb(MAX_RX_SIZE); 98 + skb = dev_alloc_skb(priv->common.rx_mtu + 32); 99 99 if (unlikely(!skb)) { 100 100 usb_free_urb(urb); 101 101 /* TODO check rx queue length and refill *somewhere* */ ··· 145 145 struct p54u_rx_info *info; 146 146 147 147 while (skb_queue_len(&priv->rx_queue) < 32) { 148 - skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL); 148 + skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL); 149 149 if (!skb) 150 150 break; 151 151 entry = usb_alloc_urb(0, GFP_KERNEL); ··· 153 153 kfree_skb(skb); 154 154 break; 155 155 } 156 - usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), MAX_RX_SIZE, p54u_rx_cb, skb); 156 + usb_fill_bulk_urb(entry, priv->udev, 157 + usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), 158 + skb_tail_pointer(skb), 159 + priv->common.rx_mtu + 32, p54u_rx_cb, skb); 157 160 info = (struct p54u_rx_info *) skb->cb; 158 161 info->urb = entry; 159 162 info->dev = dev; ··· 415 412 goto err_req_fw_failed; 416 413 } 417 414 418 - p54_parse_firmware(dev, fw_entry); 415 + err = p54_parse_firmware(dev, fw_entry); 416 + if (err) 417 + goto err_upload_failed; 419 418 420 419 left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size); 421 420 strcpy(buf, start_string); ··· 554 549 return err; 555 550 } 556 551 557 - p54_parse_firmware(dev, fw_entry); 552 + err = p54_parse_firmware(dev, fw_entry); 553 + if (err) { 554 + kfree(buf); 555 + release_firmware(fw_entry); 556 + return err; 557 + } 558 558 559 559 #define P54U_WRITE(type, addr, data) \ 560 560 do {\