Skip to content

Commit

Permalink
p54: enhance firmware parser to reduce memory waste
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Christian Lamparter authored and John W. Linville committed Sep 5, 2008
1 parent 0c25970 commit 4e416a6
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 27 deletions.
6 changes: 4 additions & 2 deletions drivers/net/wireless/p54/p54.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ struct p54_control_hdr {
} __attribute__ ((packed));

#define EEPROM_READBACK_LEN (sizeof(struct p54_control_hdr) + 4 /* p54_eeprom_lm86 */)
#define MAX_RX_SIZE (IEEE80211_MAX_RTS_THRESHOLD + sizeof(struct p54_control_hdr) + 20 /* length of struct p54_rx_hdr */ + 16 )

#define ISL38XX_DEV_FIRMWARE_ADDR 0x20000

Expand All @@ -53,6 +52,9 @@ struct p54_common {
void (*stop)(struct ieee80211_hw *dev);
int mode;
u16 seqno;
u16 rx_mtu;
u8 headroom;
u8 tailroom;
struct mutex conf_mutex;
u8 mac_addr[ETH_ALEN];
u8 bssid[ETH_ALEN];
Expand All @@ -70,7 +72,7 @@ struct p54_common {
};

int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
void p54_fill_eeprom_readback(struct p54_control_hdr *hdr);
struct ieee80211_hw *p54_init_common(size_t priv_data_len);
Expand Down
36 changes: 24 additions & 12 deletions drivers/net/wireless/p54/p54common.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,7 @@ static struct ieee80211_supported_band band_2GHz = {
.n_bitrates = ARRAY_SIZE(p54_rates),
};


void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
{
struct p54_common *priv = dev->priv;
struct bootrec_exp_if *exp_if;
Expand All @@ -79,7 +78,7 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
int i;

if (priv->rx_start)
return;
return 0;

while (data < end_data && *data)
data++;
Expand Down Expand Up @@ -117,11 +116,22 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
if (strnlen((unsigned char*)bootrec->data, 24) < 24)
fw_version = (unsigned char*)bootrec->data;
break;
case BR_CODE_DESCR:
priv->rx_start = le32_to_cpu(((__le32 *)bootrec->data)[1]);
case BR_CODE_DESCR: {
struct bootrec_desc *desc =
(struct bootrec_desc *)bootrec->data;
priv->rx_start = le32_to_cpu(desc->rx_start);
/* FIXME add sanity checking */
priv->rx_end = le32_to_cpu(((__le32 *)bootrec->data)[2]) - 0x3500;
priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500;
priv->headroom = desc->headroom;
priv->tailroom = desc->tailroom;
if (bootrec->len == 11)
priv->rx_mtu = (size_t) le16_to_cpu(
(__le16)bootrec->data[10]);
else
priv->rx_mtu = (size_t)
0x620 - priv->tx_hdr_len;
break;
}
case BR_CODE_EXPOSED_IF:
exp_if = (struct bootrec_exp_if *) bootrec->data;
for (i = 0; i < (len * sizeof(*exp_if) / 4); i++)
Expand Down Expand Up @@ -152,6 +162,8 @@ void p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw)
priv->tx_stats[7].limit = 1;
dev->queues = 4;
}

return 0;
}
EXPORT_SYMBOL_GPL(p54_parse_firmware);

Expand Down Expand Up @@ -428,7 +440,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data;
struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data;
struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
u32 addr = le32_to_cpu(hdr->req_id) - 0x70;
u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
struct memrecord *range = NULL;
u32 freed = 0;
u32 last_addr = priv->rx_start;
Expand Down Expand Up @@ -550,7 +562,7 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
u32 target_addr = priv->rx_start;
unsigned long flags;
unsigned int left;
len = (len + 0x170 + 3) & ~0x3; /* 0x70 headroom, 0x100 tailroom */
len = (len + priv->headroom + priv->tailroom + 3) & ~0x3;

spin_lock_irqsave(&priv->tx_queue.lock, flags);
left = skb_queue_len(&priv->tx_queue);
Expand Down Expand Up @@ -585,13 +597,14 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
range->start_addr = target_addr;
range->end_addr = target_addr + len;
__skb_queue_after(&priv->tx_queue, target_skb, skb);
if (largest_hole < IEEE80211_MAX_RTS_THRESHOLD + 0x170 +
if (largest_hole < priv->rx_mtu + priv->headroom +
priv->tailroom +
sizeof(struct p54_control_hdr))
ieee80211_stop_queues(dev);
}
spin_unlock_irqrestore(&priv->tx_queue.lock, flags);

data->req_id = cpu_to_le32(target_addr + 0x70);
data->req_id = cpu_to_le32(target_addr + priv->headroom);
}

static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb)
Expand Down Expand Up @@ -704,7 +717,7 @@ static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type,
filter->antenna = antenna;
filter->magic3 = cpu_to_le32(magic3);
filter->rx_addr = cpu_to_le32(priv->rx_end);
filter->max_rx = cpu_to_le16(0x0620); /* FIXME: for usb ver 1.. maybe */
filter->max_rx = cpu_to_le16(priv->rx_mtu);
filter->rxhw = priv->rxhw;
filter->magic8 = cpu_to_le16(magic8);
filter->magic9 = cpu_to_le16(magic9);
Expand Down Expand Up @@ -1084,7 +1097,6 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
priv->tx_stats[3].limit = 1;
priv->tx_stats[4].limit = 5;
dev->queues = 1;

dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 +
sizeof(struct p54_tx_control_allocdata);

Expand Down
11 changes: 11 additions & 0 deletions drivers/net/wireless/p54/p54common.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,17 @@ struct bootrec_exp_if {
__le16 top_compat;
} __attribute__((packed));

struct bootrec_desc {
__le16 modes;
__le16 flags;
__le32 rx_start;
__le32 rx_end;
u8 headroom;
u8 tailroom;
u8 unimportant[6];
u8 rates[16];
} __attribute__((packed));

#define BR_CODE_MIN 0x80000000
#define BR_CODE_COMPONENT_ID 0x80000001
#define BR_CODE_COMPONENT_VERSION 0x80000002
Expand Down
23 changes: 15 additions & 8 deletions drivers/net/wireless/p54/p54pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,11 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev)
return err;
}

p54_parse_firmware(dev, fw_entry);
err = p54_parse_firmware(dev, fw_entry);
if (err) {
release_firmware(fw_entry);
return err;
}

data = (__le32 *) fw_entry->data;
remains = fw_entry->size;
Expand Down Expand Up @@ -258,17 +262,17 @@ static void p54p_refill_rx_ring(struct ieee80211_hw *dev,
if (!desc->host_addr) {
struct sk_buff *skb;
dma_addr_t mapping;
skb = dev_alloc_skb(MAX_RX_SIZE);
skb = dev_alloc_skb(priv->common.rx_mtu + 32);
if (!skb)
break;

mapping = pci_map_single(priv->pdev,
skb_tail_pointer(skb),
MAX_RX_SIZE,
priv->common.rx_mtu + 32,
PCI_DMA_FROMDEVICE);
desc->host_addr = cpu_to_le32(mapping);
desc->device_addr = 0; // FIXME: necessary?
desc->len = cpu_to_le16(MAX_RX_SIZE);
desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
desc->flags = 0;
rx_buf[i] = skb;
}
Expand Down Expand Up @@ -311,12 +315,13 @@ static void p54p_check_rx_ring(struct ieee80211_hw *dev, u32 *index,
if (p54_rx(dev, skb)) {
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
priv->common.rx_mtu + 32,
PCI_DMA_FROMDEVICE);
rx_buf[i] = NULL;
desc->host_addr = 0;
} else {
skb_trim(skb, 0);
desc->len = cpu_to_le16(MAX_RX_SIZE);
desc->len = cpu_to_le16(priv->common.rx_mtu + 32);
}

i++;
Expand Down Expand Up @@ -534,7 +539,8 @@ static void p54p_stop(struct ieee80211_hw *dev)
if (desc->host_addr)
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
priv->common.rx_mtu + 32,
PCI_DMA_FROMDEVICE);
kfree_skb(priv->rx_buf_data[i]);
priv->rx_buf_data[i] = NULL;
}
Expand All @@ -544,7 +550,8 @@ static void p54p_stop(struct ieee80211_hw *dev)
if (desc->host_addr)
pci_unmap_single(priv->pdev,
le32_to_cpu(desc->host_addr),
MAX_RX_SIZE, PCI_DMA_FROMDEVICE);
priv->common.rx_mtu + 32,
PCI_DMA_FROMDEVICE);
kfree_skb(priv->rx_buf_mgmt[i]);
priv->rx_buf_mgmt[i] = NULL;
}
Expand Down
20 changes: 15 additions & 5 deletions drivers/net/wireless/p54/p54usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ static void p54u_rx_cb(struct urb *urb)
skb_pull(skb, sizeof(struct net2280_tx_hdr));

if (p54_rx(dev, skb)) {
skb = dev_alloc_skb(MAX_RX_SIZE);
skb = dev_alloc_skb(priv->common.rx_mtu + 32);
if (unlikely(!skb)) {
usb_free_urb(urb);
/* TODO check rx queue length and refill *somewhere* */
Expand Down Expand Up @@ -145,15 +145,18 @@ static int p54u_init_urbs(struct ieee80211_hw *dev)
struct p54u_rx_info *info;

while (skb_queue_len(&priv->rx_queue) < 32) {
skb = __dev_alloc_skb(MAX_RX_SIZE, GFP_KERNEL);
skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL);
if (!skb)
break;
entry = usb_alloc_urb(0, GFP_KERNEL);
if (!entry) {
kfree_skb(skb);
break;
}
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);
usb_fill_bulk_urb(entry, priv->udev,
usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA),
skb_tail_pointer(skb),
priv->common.rx_mtu + 32, p54u_rx_cb, skb);
info = (struct p54u_rx_info *) skb->cb;
info->urb = entry;
info->dev = dev;
Expand Down Expand Up @@ -412,7 +415,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev)
goto err_req_fw_failed;
}

p54_parse_firmware(dev, fw_entry);
err = p54_parse_firmware(dev, fw_entry);
if (err)
goto err_upload_failed;

left = block_size = min((size_t)P54U_FW_BLOCK, fw_entry->size);
strcpy(buf, start_string);
Expand Down Expand Up @@ -549,7 +554,12 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev)
return err;
}

p54_parse_firmware(dev, fw_entry);
err = p54_parse_firmware(dev, fw_entry);
if (err) {
kfree(buf);
release_firmware(fw_entry);
return err;
}

#define P54U_WRITE(type, addr, data) \
do {\
Expand Down

0 comments on commit 4e416a6

Please sign in to comment.